home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / bin / groffer < prev    next >
Text File  |  2005-10-13  |  114KB  |  4,531 lines

  1. #!/bin/sh
  2.  
  3. # groffer - display groff files
  4.  
  5. # Source file position: <groff-source>/contrib/groffer/groffer.sh
  6.  
  7. # Copyright (C) 2001,2002,2003,2004 Free Software Foundation, Inc.
  8. # Written by Bernd Warken
  9.  
  10. # This file is part of groff version 1.19.1.
  11.  
  12. # groff is free software; you can redistribute it and/or modify it
  13. # under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation; either version 2, or (at your option)
  15. # any later version.
  16.  
  17. # groff is distributed in the hope that it will be useful, but WITHOUT
  18. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  19. # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
  20. # License for more details.
  21.  
  22. # You should have received a copy of the GNU General Public License
  23. # along with groff; see the files COPYING and LICENSE in the top
  24. # directory of the groff source.  If not, write to the Free Software
  25. # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  26.  
  27. _PROGRAM_NAME='groffer';
  28. _PROGRAM_VERSION='0.9.7';
  29. _LAST_UPDATE='30 Apr 2004';
  30.  
  31.  
  32. ########################################################################
  33. # Determine the shell under which to run this script;
  34. # if `ash' is available restart the script using `ash';
  35. # otherwise just go on.
  36.  
  37. if test "${_groffer_run}" = ''; then
  38.   # only reached during the first run of the script
  39.  
  40.   export _PROGRAM_NAME;
  41.   export _PROGRAM_VERSION;
  42.   export _LAST_UPDATE;
  43.  
  44.   export GROFFER_OPT;        # option environment for groffer
  45.   export _GROFFER_SH;        # file name of this shell script
  46.   export _OUTPUT_FILE_NAME;    # output generated, see main_set_res..()
  47.   export _groffer_run;        # counter for the runs of groffer
  48.  
  49.   _groffer_run='first';
  50.  
  51.   case "$0" in
  52.   *${_PROGRAM_NAME}*)
  53.     _GROFFER_SH="$0";
  54.     # was: _GROFFER_SH="/usr/bin/${_PROGRAM_NAME}";
  55.     ;;
  56.   *)
  57.     echo "The ${_PROGRAM_NAME} script should be started directly." >&2
  58.     exit 1;
  59.     ;;
  60.   esac;
  61.  
  62.   ###########################
  63.   # _get_opt_shell ("$@")
  64.   #
  65.   # Determine whether `--shell' was specified in $GROFF_OPT or in $*;
  66.   # if so echo its argument.
  67.   #
  68.   _get_opt_shell()
  69.   {
  70.     local i;
  71.     local _sh;
  72.     case " ${GROFFER_OPT} $*" in
  73.       *\ --shell\ *|*\ --shell=*)
  74.         (
  75.           eval set -- "${GROFFER_OPT}" '"$@"';
  76.           _sh='';
  77.           for i in "$@"; do
  78.             case "$1" in
  79.               --shell)
  80.                 if test "$#" -ge 2; then
  81.                   _sh="$2";
  82.                   shift;
  83.                 fi;
  84.                 ;;
  85.               --shell=?*)
  86.                 # delete up to first `=' character
  87.                 _sh="$(echo -n "$1" | sed -e 's/^[^=]*=//')";
  88.                 ;;
  89.             esac;
  90.             shift;
  91.           done;
  92.           echo -n "${_sh}";
  93.         )
  94.         ;;
  95.     esac;
  96.   }
  97.  
  98.  
  99.   ###########################
  100.   # _test_on_shell (<name>)
  101.   #
  102.   # Test whether <name> is a shell program of Bourne type (POSIX sh).
  103.   #
  104.   _test_on_shell()
  105.   {
  106.     if test "$#" -le 0 || test "$1" = ''; then
  107.       return 1;
  108.     fi;
  109.     # do not quote $1 to allow arguments
  110.     test "$($1 -c 's=ok; echo -n "$s"' 2>/dev/null)" = 'ok';
  111.   }
  112.  
  113.   # do the shell determination
  114.   _shell="$(_get_opt_shell "$@")";
  115.   if test "${_shell}" = ''; then
  116.     _shell='ash';
  117.   fi;
  118.   if _test_on_shell "${_shell}"; then
  119.     _groffer_run='second';
  120.     # do not quote $_shell to allow arguments
  121.     exec ${_shell} "${_GROFFER_SH}" "$@";
  122.     exit;
  123.   fi;
  124.  
  125.   # clean-up of shell determination
  126.   unset _shell;
  127.   unset _GROFFER_SH;
  128.   unset _groffer_run;
  129.   _get_opt_shell()
  130.   {
  131.     return 0;
  132.   }
  133.   _test_on_shell()
  134.   {
  135.     return 0;
  136.   }
  137.  
  138. fi; # end of first run
  139.  
  140. if test "${_groffer_run}" != 'second';
  141. then
  142.   echo "$_groffer_run should be 'second' here." >&2
  143.   exit 1
  144. fi;
  145. unset _groffer_run
  146.  
  147.  
  148. ########################################################################
  149. # diagnostic messages
  150. #
  151. export _DEBUG;
  152. _DEBUG='no';            # disable debugging information
  153. #_DEBUG='yes';            # enable debugging information
  154.  
  155. export _DEBUG_LM;
  156. _DEBUG_LM='no';            # disable landmark messages
  157. #_DEBUG_LM='yes';        # enable landmark messages
  158.  
  159.  
  160. ########################################################################
  161. #                       Environment Variables
  162. ########################################################################
  163.  
  164. # Environment variables that exist only for this file start with an
  165. # underscore letter.  Global variables to this file are written in
  166. # upper case letters, e.g. $_GLOBAL_VARIABLE; temporary variables
  167. # start with an underline and use only lower case letters and
  168. # underlines, e.g.  $_local_variable .
  169.  
  170. #   [A-Z]*     system variables,      e.g. $MANPATH
  171. #   _[A-Z_]*   global file variables, e.g. $_MAN_PATH
  172. #   _[a-z_]*   temporary variables,   e.g. $_manpath
  173.  
  174. # Due to incompatibilities of the `ash' shell, the name of loop
  175. # variables in `for' must be single character
  176. #   [a-z]      local loop variables,   e.g. $i
  177.  
  178.  
  179. ########################################################################
  180. # read-only variables (global to this file)
  181. ########################################################################
  182.  
  183. # characters
  184.  
  185. export _BQUOTE;
  186. export _BSLASH;
  187. export _DQUOTE;
  188. export _NEWLINE;
  189. export _LBRACK;
  190. export _LPAR;
  191. export _RBRACK;
  192. export _RPAR;
  193. export _SPACE;
  194. export _SQUOTE;
  195. export _TAB;
  196.  
  197. _BQUOTE='`';
  198. _BSLASH='\';
  199. _DQUOTE='"';
  200. _NEWLINE='
  201. ';
  202. _LBRACK='[';
  203. _LPAR='(';
  204. _RBRACK=']';
  205. _RPAR=')';
  206. _SPACE=' ';
  207. _SQUOTE="'";
  208. _TAB='    ';
  209.  
  210. # function return values; `0' means ok; other values are error codes
  211. export _ALL_EXIT;
  212. export _BAD;
  213. export _ERROR;
  214. export _GOOD;
  215. export _NO;
  216. export _OK;
  217. export _YES;
  218.  
  219. _GOOD='0';            # return ok
  220. _BAD='1';            # return negatively, error code `1'
  221. _ERROR='7';            # for syntax errors; no `-1' in `ash'
  222.  
  223. _ALL_EXIT="${_GOOD} ${_BAD} ${_ERROR}"; # all exit codes (for `trap_set')
  224.  
  225. _NO="${_BAD}";
  226. _YES="${_GOOD}";
  227. _OK="${_GOOD}";
  228.  
  229. # quasi-functions, call with `eval'
  230. export return_ok;
  231. export return_good;
  232. export return_bad;
  233. export return_yes;
  234. export return_no;
  235. export return_error;
  236. return_ok="func_pop; return ${_OK}";
  237. return_good="func_pop; return ${_GOOD}";
  238. return_bad="func_pop; return ${_BAD}";
  239. return_yes="func_pop; return ${_YES}";
  240. return_no="func_pop; return ${_NO}";
  241. return_error="func_pop; return ${_ERROR}";
  242.  
  243.  
  244. export _CONFFILES;
  245. _CONFFILES="/etc/groff/groffer.conf ${HOME}/.groff/groffer.conf";
  246.  
  247. export _DEFAULT_MODES;
  248. _DEFAULT_MODES='x,ps,tty';
  249. export _DEFAULT_RESOLUTION;
  250. _DEFAULT_RESOLUTION='75';
  251.  
  252. export _DEFAULT_TTY_DEVICE;
  253. _DEFAULT_TTY_DEVICE='latin1';
  254.  
  255. # _VIEWER_* viewer programs for different modes (only X is necessary)
  256. # _VIEWER_* a comma-separated list of viewer programs (with options)
  257. export _VIEWER_DVI;        # viewer program for dvi mode
  258. export _VIEWER_PS;        # viewer program for ps mode
  259. export _VIEWER_HTML_X;        # viewer program for html mode in X
  260. export _VIEWER_HTML_TTY;    # viewer program for html mode in tty
  261. _VIEWER_DVI='xdvi,dvilx';
  262. _VIEWER_PDF='xpdf,acroread';
  263. _VIEWER_PS='gv,ghostview,gs_x11,gs';
  264. _VIEWER_HTML='konqueror,mozilla,netscape,opera,amaya,arena,lynx';
  265. _VIEWER_X='gxditview,xditview';
  266.  
  267. # Search automatically in standard sections `1' to `8', and in the
  268. # traditional sections `9', `n', and `o'.  On many systems, there
  269. # exist even more sections, mostly containing a set of man pages
  270. # special to a specific program package.  These aren't searched for
  271. # automatically, but must be specified on the command line.
  272. export _MAN_AUTO_SEC;
  273. _MAN_AUTO_SEC="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'"
  274.  
  275. export _PROCESS_ID;        # for shutting down the program
  276. _PROCESS_ID="$$";
  277.  
  278.  
  279. ############ the command line options of the involved programs
  280. #
  281. # The naming scheme for the options environment names is
  282. # $_OPTS_<prog>_<length>[_<argspec>]
  283. #
  284. # <prog>:    program name GROFFER, GROFF, or CMDLINE (for all
  285. #            command line options)
  286. # <length>:  LONG (long options) or SHORT (single character options)
  287. # <argspec>: ARG for options with argument, NA for no argument;
  288. #            without _<argspec> both the ones with and without arg.
  289. #
  290. # Each option that takes an argument must be specified with a
  291. # trailing : (colon).
  292.  
  293. # exports
  294. export _OPTS_GROFFER_SHORT_NA;
  295. export _OPTS_GROFFER_SHORT_ARG;
  296. export _OPTS_GROFFER_LONG_NA;
  297. export _OPTS_GROFFER_LONG_ARG;
  298. export _OPTS_GROFF_SHORT_NA;
  299. export _OPTS_GROFF_SHORT_ARG;
  300. export _OPTS_GROFF_LONG_NA;
  301. export _OPTS_GROFF_LONG_ARG;
  302. export _OPTS_X_SHORT_ARG;
  303. export _OPTS_X_SHORT_NA;
  304. export _OPTS_X_LONG_ARG;
  305. export _OPTS_X_LONG_NA;
  306. export _OPTS_MAN_SHORT_ARG;
  307. export _OPTS_MAN_SHORT_NA;
  308. export _OPTS_MAN_LONG_ARG;
  309. export _OPTS_MAN_LONG_NA;
  310. export _OPTS_MANOPT_SHORT_ARG;
  311. export _OPTS_MANOPT_SHORT_NA;
  312. export _OPTS_MANOPT_LONG_ARG;
  313. export _OPTS_MANOPT_LONG_NA;
  314. export _OPTS_CMDLINE_SHORT_NA;
  315. export _OPTS_CMDLINE_SHORT_ARG;
  316. export _OPTS_CMDLINE_LONG_NA;
  317. export _OPTS_CMDLINE_LONG_ARG;
  318.  
  319. ###### groffer native options
  320.  
  321. _OPTS_GROFFER_SHORT_NA="'h' 'Q' 'v' 'V' 'X' 'Z'";
  322. _OPTS_GROFFER_SHORT_ARG="'T'";
  323.  
  324. _OPTS_GROFFER_LONG_NA="'auto' 'debug' 'default' 'dvi' \
  325. 'groff' 'help' 'intermediate-output' 'html' 'man' \
  326. 'no-location' 'no-man' 'pdf' 'ps' 'rv' 'source' 'text' 'text-device' \
  327. 'title' 'tty' 'tty-device' 'version' 'whatis' 'where' 'www' 'x' 'X'";
  328.  
  329. _OPTS_GROFFER_LONG_ARG="\
  330. 'apropos' 'apropos-data' 'apropos-devel' 'apropos-progs' \
  331. 'default-modes' 'dvi-viewer' 'extension' 'fg' 'fn' 'font' \
  332. 'foreground' 'html-viewer' 'mode' 'pdf-viewer' 'ps-viewer' 'shell' \
  333. 'tty-viewer' 'www-viewer' 'x-viewer' 'X-viewer'";
  334.  
  335. ##### groffer options inhereted from groff
  336.  
  337. _OPTS_GROFF_SHORT_NA="'a' 'b' 'c' 'C' 'e' 'E' 'g' 'G' 'i' 'l' 'N' 'p' \
  338. 'R' 's' 'S' 't' 'U' 'V' 'z'";
  339. _OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'L' 'm' 'M' 'n' 'o' 'P' 'r' \
  340. 'w' 'W'";
  341. _OPTS_GROFF_LONG_NA="'source'";
  342. _OPTS_GROFF_LONG_ARG="'device' 'macro-file'";
  343.  
  344. ##### groffer options inhereted from the X Window toolkit
  345.  
  346. _OPTS_X_SHORT_NA="";
  347. _OPTS_X_SHORT_ARG="";
  348.  
  349. _OPTS_X_LONG_NA="'iconic' 'rv'";
  350.  
  351. _OPTS_X_LONG_ARG="'background' 'bd' 'bg' 'bordercolor' 'borderwidth' \
  352. 'bw' 'display' 'fg' 'fn' 'font' 'foreground' 'ft', 'geometry'
  353. 'resolution' 'title' 'xrm'";
  354.  
  355. ###### groffer options inherited from man
  356.  
  357. _OPTS_MAN_SHORT_NA="";
  358. _OPTS_MAN_SHORT_ARG="";
  359.  
  360. _OPTS_MAN_LONG_NA="'all' 'ascii' 'catman' 'debug' 'ditroff' 'help' \
  361. 'local-file' 'location' 'pager' 'troff' 'update' 'version' \
  362. 'whatis' 'where'";
  363.  
  364. _OPTS_MAN_LONG_ARG="'extension' 'locale' 'manpath' \
  365. 'pager' 'preprocessor' 'prompt' 'sections' 'systems' 'troff-device'";
  366.  
  367. ###### additional options for parsing $MANOPT only
  368.  
  369. _OPTS_MANOPT_SHORT_NA="'7' 'a' 'c' 'd' 'D' 'f' 'h' 'k' 'l' 't' 'u' \
  370. 'V' 'w' 'Z'";
  371. _OPTS_MANOPT_SHORT_ARG="'e' 'L' 'm' 'M' 'p' 'P' 'r' 'S' 'T'";
  372.  
  373. _OPTS_MANOPT_LONG_NA="${_OPTS_MAN_LONG_NA} \
  374. 'apropos' 'debug' 'default' 'html' 'ignore-case' 'location-cat' \
  375. 'match-case' 'troff' 'update' 'version' 'where-cat'";
  376.  
  377. _OPTS_MANOPT_LONG_ARG="${_OPTS_MAN_LONG_NA} \
  378. 'config_file' 'encoding' 'locale'";
  379.  
  380. ###### collections of command line options
  381.  
  382. _OPTS_CMDLINE_SHORT_NA="${_OPTS_GROFFER_SHORT_NA}\
  383. ${_OPTS_GROFF_SHORT_NA} ${_OPTS_X_SHORT_NA} ${_OPTS_MAN_SHORT_NA}";
  384. _OPTS_CMDLINE_SHORT_ARG="${_OPTS_GROFFER_SHORT_ARG} \
  385. ${_OPTS_GROFF_SHORT_ARG} ${_OPTS_X_SHORT_ARG} ${_OPTS_MAN_SHORT_ARG}";
  386.  
  387. _OPTS_CMDLINE_LONG_NA="${_OPTS_GROFFER_LONG_NA} \
  388. ${_OPTS_GROFF_LONG_NA} ${_OPTS_X_LONG_NA} ${_OPTS_MAN_LONG_NA}";
  389. _OPTS_CMDLINE_LONG_ARG="${_OPTS_GROFFER_LONG_ARG} \
  390. ${_OPTS_GROFF_LONG_ARG} ${_OPTS_MAN_LONG_ARG} ${_OPTS_X_LONG_ARG}";
  391.  
  392.  
  393. ########################################################################
  394. # read-write variables (global to this file)
  395. ########################################################################
  396.  
  397. export _ADDOPTS_GROFF;        # Transp. options for groff (`eval').
  398. export _ADDOPTS_POST;        # Transp. options postproc (`eval').
  399. export _ADDOPTS_X;        # Transp. options X postproc (`eval').
  400. export _DEFAULT_MODES;        # Set default modes.
  401. export _DISPLAY_MODE;        # Display mode.
  402. export _DISPLAY_PROG;        # Viewer program to be used for display.
  403. export _DISPLAY_ARGS;        # X resources for the viewer program.
  404. export _FILEARGS;        # Stores filespec parameters.
  405. export _FUNC_STACK;        # Store debugging information.
  406. export _REGISTERED_TITLE;    # Processed file names.
  407. # _HAS_* from availability tests
  408. export _HAS_COMPRESSION;    # `yes' if compression is available
  409. export _HAS_OPTS_GNU;        # `yes' if GNU `getopt' is available
  410. export _HAS_OPTS_POSIX;        # `yes' if POSIX `getopts' is available
  411. # _MAN_* finally used configuration of man searching
  412. export _MAN_ALL;        # search all man pages per filespec
  413. export _MAN_ENABLE;        # enable search for man pages
  414. export _MAN_EXT;        # extension for man pages
  415. export _MAN_FORCE;        # force file parameter to be man pages
  416. export _MAN_IS_SETUP;        # setup man variables only once
  417. export _MAN_LANG;        # language for man pages
  418. export _MAN_LANG_DONE;        # language dirs added to man path
  419. export _MAN_PATH;        # search path for man pages
  420. export _MAN_SEC;        # sections for man pages; sep. `:'
  421. export _MAN_SEC_DONE;        # sections added to man path
  422. export _MAN_SYS;        # system names for man pages; sep. `,'
  423. export _MAN_SYS;        # system names added to man path
  424. # _MANOPT_* as parsed from $MANOPT
  425. export _MANOPT_ALL;        # $MANOPT --all
  426. export _MANOPT_EXTENSION;    # $MANOPT --extension
  427. export _MANOPT_LANG;        # $MANOPT --locale
  428. export _MANOPT_PATH;        # $MANOPT --manpath
  429. export _MANOPT_PAGER;        # $MANOPT --pager
  430. export _MANOPT_SEC;        # $MANOPT --sections
  431. export _MANOPT_SYS;        # $MANOPT --systems
  432. # _OPT_* as parsed from groffer command line
  433. export _OPT_ALL;        # display all suitable man pages.
  434. export _OPT_APROPOS;        # call `apropos' program.
  435. export _OPT_APROPOS_DATA;    # `apropos' for man sections 4, 5, 7
  436. export _OPT_APROPOS_DEVEL;    # `apropos' for man sections 2, 3, 9
  437. export _OPT_APROPOS_PROGS;    # `apropos' for man sections 1, 6, 8
  438. export _OPT_BD;            # set border color in some modes.
  439. export _OPT_BG;            # set background color in some modes.
  440. export _OPT_BW;            # set border width in some modes.
  441. export _OPT_DEBUG;        # print debugging information on stderr.
  442. export _OPT_DEFAULT_MODES;    # `,'-list of modes when no mode given.
  443. export _OPT_DEVICE;        # device option.
  444. export _OPT_DISPLAY;        # set X display.
  445. export _OPT_FG;            # set foreground color in some modes.
  446. export _OPT_FN;            # set font in some modes.
  447. export _OPT_GEOMETRY;        # set size and position of viewer in X.
  448. export _OPT_ICONIC;        # -iconic option for X viewers.
  449. export _OPT_LANG;        # set language for man pages
  450. export _OPT_LOCATION;        # print processed file names to stderr
  451. export _OPT_MODE;        # values: X, tty, Q, Z, ""
  452. export _OPT_MANPATH;        # manual setting of path for man-pages
  453. export _OPT_PAGER;        # specify paging program for tty mode
  454. export _OPT_RESOLUTION;        # set X resolution in dpi
  455. export _OPT_RV;            # reverse fore- and background colors.
  456. export _OPT_SECTIONS;        # sections for man page search
  457. export _OPT_SYSTEMS;        # man pages of different OS's
  458. export _OPT_TITLE;        # title for gxditview window
  459. export _OPT_TEXT_DEVICE;        # set device for tty mode.
  460. export _OPT_V;            # groff option -V.
  461. export _OPT_VIEWER_DVI;        # viewer program for dvi mode
  462. export _OPT_VIEWER_PDF;        # viewer program for pdf mode
  463. export _OPT_VIEWER_PS;        # viewer program for ps mode
  464. export _OPT_VIEWER_HTML;    # viewer program for html mode
  465. export _OPT_VIEWER_X;        # viewer program for x mode
  466. export _OPT_WHATIS;        # print the one-liner man info
  467. export _OPT_XRM;        # specify X resource.
  468. export _OPT_Z;            # groff option -Z.
  469. # _TMP_* temporary files
  470. export _TMP_DIR;        # groff directory for temporary files
  471. export _TMP_DIR_SUB;        # groffer directory for temporary files
  472. export _TMP_CAT;        # stores concatenation of everything
  473. export _TMP_STDIN;        # stores stdin, if any
  474.  
  475. # these variables are preset in section `Preset' after the rudim. test
  476.  
  477.  
  478. ########################################################################
  479. #             Test of rudimentary shell functionality
  480. ########################################################################
  481.  
  482.  
  483. ########################################################################
  484. # Test of `test'.
  485. #
  486. test "a" = "a" || exit 1;
  487.  
  488.  
  489. ########################################################################
  490. # Test of `echo' and the `$()' construct.
  491. #
  492. echo -n '' >/dev/null || exit "${_ERROR}";
  493. if test "$(echo -n 'te' && echo -n '' && echo -n 'st')" != "test"; then
  494.   exit "${_ERROR}";
  495. fi;
  496.  
  497.  
  498. ########################################################################
  499. # Test of function definitions.
  500. #
  501. _t_e_s_t_f_u_n_c_()
  502. {
  503.   return "${_OK}";
  504. }
  505.  
  506. if _t_e_s_t_f_u_n_c_ 2>/dev/null; then
  507.   :
  508. else
  509.   echo 'shell does not support function definitions.' >&2;
  510.   exit "${_ERROR}";
  511. fi;
  512.  
  513.  
  514. ########################################################################
  515. # Preset and reset of read-write global variables
  516. ########################################################################
  517.  
  518.  
  519. # For variables that can be reset by option `--default', see reset().
  520.  
  521. _FILEARGS='';
  522.  
  523. # _HAS_* from availability tests
  524. _HAS_COMPRESSION='';
  525. _HAS_OPTS_GNU='';
  526. _HAS_OPTS_POSIX='';
  527.  
  528. # _TMP_* temporary files
  529. _TMP_DIR='';
  530. _TMP_DIR_SUB='';
  531. _TMP_CAT='';
  532. _TMP_STDIN='';
  533.  
  534.  
  535. ########################################################################
  536. # reset ()
  537. #
  538. # Reset the variables that can be affected by options to their default.
  539. #
  540. reset()
  541. {
  542.   if test "$#" -ne 0; then
  543.     error "reset() does not have arguments.";
  544.   fi;
  545.  
  546.   _ADDOPTS_GROFF='';
  547.   _ADDOPTS_POST='';
  548.   _ADDOPTS_X='';
  549.   _DISPLAY_ARGS='';
  550.   _DISPLAY_MODE='';
  551.   _DISPLAY_PROG='';
  552.   _REGISTERED_TITLE='';
  553.  
  554.   # _MAN_* finally used configuration of man searching
  555.   _MAN_ALL='no';
  556.   _MAN_ENABLE='yes';        # do search for man-pages
  557.   _MAN_EXT='';
  558.   _MAN_FORCE='no';        # first local file, then search man page
  559.   _MAN_IS_SETUP='no';
  560.   _MAN_LANG='';
  561.   _MAN_LANG_DONE='no';
  562.   _MAN_PATH='';
  563.   _MAN_SEC='';
  564.   _MAN_SEC_DONE='no';
  565.   _MAN_SYS='';
  566.   _MAN_SYS_DONE='no';
  567.  
  568.   # _MANOPT_* as parsed from $MANOPT
  569.   _MANOPT_ALL='no';
  570.   _MANOPT_EXTENSION='';
  571.   _MANOPT_LANG='';
  572.   _MANOPT_PATH='';
  573.   _MANOPT_PAGER='';
  574.   _MANOPT_SEC='';
  575.   _MANOPT_SYS='';
  576.  
  577.   # _OPT_* as parsed from groffer command line
  578.   _OPT_ALL='no';
  579.   _OPT_APROPOS='';
  580.   _OPT_APROPOS_DATA='';
  581.   _OPT_APROPOS_DEVEL='';
  582.   _OPT_APROPOS_PROGS='';
  583.   _OPT_BD='';
  584.   _OPT_BG='';
  585.   _OPT_BW='';
  586.   _OPT_DEBUG='no';
  587.   _OPT_DEFAULT_MODES='';
  588.   _OPT_DEVICE='';
  589.   _OPT_DISPLAY='';
  590.   _OPT_FG='';
  591.   _OPT_FN='';
  592.   _OPT_GEOMETRY='';
  593.   _OPT_ICONIC='no';
  594.   _OPT_LANG='';
  595.   _OPT_LOCATION='no';
  596.   _OPT_MODE='';
  597.   _OPT_MANPATH='';
  598.   _OPT_PAGER='';
  599.   _OPT_RESOLUTION='';
  600.   _OPT_RV='no';
  601.   _OPT_SECTIONS='';
  602.   _OPT_SYSTEMS='';
  603.   _OPT_TITLE='';
  604.   _OPT_TEXT_DEVICE='';
  605.   _OPT_V='no';
  606.   _OPT_VIEWER_DVI='';
  607.   _OPT_VIEWER_PDF='';
  608.   _OPT_VIEWER_PS='';
  609.   _OPT_VIEWER_HTML='';
  610.   _OPT_VIEWER_X='';
  611.   _OPT_WHATIS='no';
  612.   _OPT_XRM='';
  613.   _OPT_Z='no';
  614.  
  615. }
  616.  
  617. reset;
  618.  
  619.  
  620. ########################################################################
  621. #          Functions for error handling and debugging
  622. ########################################################################
  623.  
  624.  
  625. ##############
  626. # landmark (<text>)
  627. #
  628. # Print <text> to standard error as a debugging aid.
  629. #
  630. # Globals: $_DEBUG_LM
  631. #
  632. landmark()
  633. {
  634.   if test "${_DEBUG_LM}" = 'yes'; then
  635.     echo ">>> $*" >&2;
  636.   fi;
  637. }
  638.  
  639. landmark "1: debugging functions";
  640.  
  641.  
  642. ##############
  643. # clean_up ()
  644. #
  645. # Clean up at exit.
  646. #
  647. clean_up()
  648. {
  649.   if test -d "${_TMP_DIR}"; then
  650.     rm -f "${_TMP_DIR}"/*;
  651.     rmdir "${_TMP_DIR}";
  652.   fi;
  653. }
  654.  
  655.  
  656. ##############
  657. # echo2 (<text>*)
  658. #
  659. # Output to stderr.
  660. #
  661. # Arguments : arbitrary text.
  662. #
  663. echo2()
  664. {
  665.   echo "$*" >&2;
  666. }
  667.  
  668.  
  669. ##############
  670. # echo2n (<text>*)
  671. #
  672. # Output to stderr.
  673. #
  674. # Arguments : arbitrary text.
  675. #
  676. echo2n()
  677. {
  678.   echo -n "$*" >&2;
  679. }
  680.  
  681.  
  682. #############
  683. # diag (text>*)
  684. #
  685. # Output a diagnostic message to stderr
  686. #
  687. diag()
  688. {
  689.   echo2 '>>>>>'"$*";
  690. }
  691.  
  692.  
  693. #############
  694. # error (<text>*)
  695. #
  696. # Print an error message to standard error; exit with an error condition
  697. #
  698. error()
  699. {
  700.   local i;
  701.   local _code;
  702.   _code="${_ERROR}";
  703.   case "$#" in
  704.     0) true; ;;
  705.     1) echo2 'groffer error: '"$1"; ;;
  706.     2)
  707.       echo2 'groffer error: '"$1";
  708.       _code="$2";
  709.       ;;
  710.     *) echo2 'groffer error: wrong number of arguments in error().'; ;;
  711.   esac;
  712.   if test "${_DEBUG}" = 'yes'; then
  713.     func_stack_dump;
  714.   fi;
  715.   clean_up;
  716.   kill "${_PROCESS_ID}" >/dev/null 2>&1;
  717.   kill -9 "${_PROCESS_ID}" >/dev/null 2>&1;
  718.   exit "${_code}";
  719. }
  720.  
  721.  
  722. #############
  723. # abort (<text>*)
  724. #
  725. # Terminate program with error condition
  726. #
  727. abort()
  728. {
  729.   error "Program aborted.";
  730.   exit 1;
  731. }
  732.  
  733.  
  734. #############
  735. # func_check (<func_name> <rel_op> <nr_args> "$@")
  736. #
  737. # Check number of arguments and register to _FUNC_STACK.
  738. #
  739. # Arguments: >=3
  740. #   <func_name>: name of the calling function.
  741. #   <rel_op>:    a relational operator: = != < > <= >= 
  742. #   <nr_args>:   number of arguments to be checked against <operator>
  743. #   "$@":        the arguments of the calling function.
  744. #
  745. func_check()
  746. {
  747.   local _comp;
  748.   local _fname;
  749.   local _nargs;
  750.   local _op;
  751.   local _s;
  752.   if test "$#" -lt 3; then
  753.     error 'func_check() needs at least 3 arguments.';
  754.   fi;
  755.   _fname="$1";
  756.   case "$3" in
  757.     1)
  758.       _nargs="$3";
  759.       _s='';
  760.       ;;
  761.     0|[2-9])
  762.       _nargs="$3";
  763.       _s='s';
  764.       ;;
  765.     *)
  766.       error "func_check(): third argument must be a digit.";
  767.       ;;
  768.   esac;
  769.   case "$2" in
  770.     '='|'-eq')
  771.       _op='-eq';
  772.       _comp='exactly';
  773.       ;;
  774.     '>='|'-ge')
  775.       _op='-ge';
  776.       _comp='at least';
  777.       ;;
  778.     '<='|'-le')
  779.       _op='-le';
  780.       _comp='at most';
  781.       ;;
  782.     '<'|'-lt')
  783.       _op='-lt';
  784.       _comp='less than';
  785.       ;;
  786.     '>'|'-gt')
  787.       _op='-gt';
  788.       _comp='more than';
  789.       ;;
  790.     '!='|'-ne')
  791.       _op='-ne';
  792.       _comp='not';
  793.       ;;
  794.     *) 
  795.       error \
  796.         'func_check(): second argument is not a relational operator.';
  797.       ;;
  798.   esac;
  799.   shift 3;
  800.   if test "$#" "${_op}" "${_nargs}"; then
  801.     do_nothing;
  802.   else
  803.     error \
  804.       "${_fname}"'() needs '"${_comp} ${_nargs}"' argument'"${_s}"'.';
  805.   fi;
  806.   if test "${_DEBUG}" = 'yes'; then
  807.     func_push "${_fname} $*";
  808.   fi;
  809. }
  810.  
  811.  
  812. #############
  813. # func_pop ()
  814. #
  815. # Retrieve the top element from the stack.
  816. #
  817. # The stack elements are separated by `!'; the popped element is
  818. # identical to the original element, except that all `!' characters
  819. # were removed.
  820. #
  821. # Arguments: 1
  822. #
  823. func_pop()
  824. {
  825.   if test "${_DEBUG}" = 'yes'; then
  826.     if test "$#" -ne 0; then
  827.       error 'func_pop() does not have arguments.';
  828.     fi;
  829.     case "${_FUNC_STACK}" in
  830.       '')
  831.         error 'func_pop(): stack is empty.';
  832.         ;;
  833.       *!*)
  834.         # split at first bang `!'.
  835.         _FUNC_STACK="$(echo -n ${_FUNC_STACK} \
  836.                        | sed -e 's/^[^!]*!//')";
  837.         ;;
  838.       *)
  839.         _FUNC_STACK='';
  840.         ;;
  841.     esac;
  842.   fi;
  843. }
  844.  
  845.  
  846. #############
  847. # func_push (<element>)
  848. #
  849. # Store another element to stack.
  850. #
  851. # The stack elements are separated by `!'; if <element> contains a `!'
  852. # it is removed first.
  853. #
  854. # Arguments: 1
  855. #
  856. func_push()
  857. {
  858.   local _element;
  859.   if test "${_DEBUG}" = 'yes'; then
  860.     if test "$#" -ne 1; then
  861.       error 'func_push() needs 1 argument.';
  862.     fi;
  863.     case "$1" in
  864.       *'!'*)
  865.         # remove all bangs `!'.
  866.         _element="$(echo -n "$1" | sed -e 's/!//g')";
  867.         ;;
  868.       *)
  869.         _element="$1";
  870.         ;;
  871.     esac;
  872.     if test "${_FUNC_STACK}" = ''; then
  873.       _FUNC_STACK="${_element}";
  874.     else
  875.       _FUNC_STACK="${_element}!${_FUNC_STACK}";
  876.     fi;
  877.   fi;
  878. }
  879.  
  880.  
  881. #############
  882. # func_stack_dump ()
  883. #
  884. # Print the content of the stack.  Ignore the arguments.
  885. #
  886. func_stack_dump()
  887. {
  888.   diag 'call stack:';
  889.   case "${_FUNC_STACK}" in
  890.     *!*)
  891.       _rest="${_FUNC_STACK}";
  892.       while test "${_rest}" != ''; do
  893.         # get part before the first bang `!'.
  894.         diag "$(echo -n "${_rest}" | sed -e 's/!.*$//')";
  895.         # delete part before and including the first bang `!'.
  896.         _rest="$(echo -n "${_rest}" | sed -e 's/^[^!]*!//')";
  897.       done;
  898.       ;;
  899.     *)
  900.       diag "${_FUNC_STACK}";
  901.       ;;
  902.   esac;
  903. }
  904.  
  905.  
  906. ########################################################################
  907. #                        System Test
  908. ########################################################################
  909.  
  910. landmark "2: system test";
  911.  
  912. # Test the availability of the system utilities used in this script.
  913.  
  914.  
  915. ########################################################################
  916. # Test of `true'.
  917. #
  918. if true >/dev/null 2>&1; then
  919.   true;
  920. else
  921.   true()
  922.   {
  923.     return "${_GOOD}";
  924.   }
  925.  
  926.   false()
  927.   {
  928.     return "${_BAD}";
  929.   }
  930. fi;
  931.  
  932.  
  933. ########################################################################
  934. # Test of `unset'.
  935. #
  936. _test='test';
  937. if unset _test >/dev/null 2>&1 && test "${_test}" = ''; then
  938.   true;
  939. else
  940.   unset()
  941.   {
  942.     for v in "$@"; do
  943.       eval "$v"='';
  944.     done;
  945.   }
  946. fi;
  947. unset _test;
  948.  
  949. ########################################################################
  950. # Test of builtin `local'
  951. #
  952.  
  953. _t_e_s_t_f_u_n_c_()
  954. {
  955.   local _test >/dev/null 2>&1 || return "${_BAD}";
  956. }
  957.  
  958. if _t_e_s_t_f_u_n_c_; then
  959.   :
  960. else
  961.   local()
  962.   {
  963.     if test "$1" != ''; then
  964.       error "overriding global variable \`$1' with local value.";
  965.     fi;
  966.   }
  967. fi;
  968.  
  969.  
  970. ########################################################################
  971. # Test of global setting in functions
  972. #
  973. _global='outside';
  974. _clobber='outside';
  975.  
  976. _t_e_s_t_f_u_n_c_()
  977. {
  978.   local _clobber;
  979.   _global='inside';
  980.   _clobber='inside';
  981. }
  982.  
  983. _t_e_s_t_f_u_n_c_;
  984. if test "${_global}" != 'inside' || test "${_clobber}" != 'outside';
  985. then
  986.   error "Cannot assign to global variables from within functions.";
  987. fi;
  988.  
  989. unset _global;
  990. unset _clobber;
  991.  
  992.  
  993. ########################################################################
  994. # Test of function `sed'.
  995. #
  996. if test "$(echo xTesTx \
  997.            | sed -e 's/^.\([Tt]e*x*sTT*\).*$/\1/' \
  998.            | sed -e '\|T|s||t|g')" != 'test';
  999. then
  1000.   error 'Test of "sed" command failed.';
  1001. fi;
  1002.  
  1003.  
  1004. ########################################################################
  1005. # Test of function `cat'.
  1006. #
  1007. if test "$(echo test | cat)" != "test"; then
  1008.   error 'Test of "cat" command failed.';
  1009. fi;
  1010.  
  1011.  
  1012. ########################################################################
  1013. # Test for compression.
  1014. #
  1015. if test "$(echo 'test' | gzip -c -d -f - 2>/dev/null)" = 'test'; then
  1016.   _HAS_COMPRESSION='yes';
  1017.   if echo 'test' | bzip2 -c 2>/dev/null | bzip2 -t 2>/dev/null \
  1018.      && test "$(echo 'test' | bzip2 -c 2>/dev/null \
  1019.                             | bzip2 -d -c 2>/dev/null)" \
  1020.              = 'test'; then
  1021.     _HAS_BZIP='yes';
  1022.   else
  1023.     _HAS_BZIP='no';
  1024.   fi;
  1025. else
  1026.   _HAS_COMPRESSION='no';
  1027.   _HAS_BZIP='no';
  1028. fi;
  1029.  
  1030.  
  1031. ########################################################################
  1032. _t_e_s_t_f_u_n_c_()
  1033. {
  1034.   :
  1035. }
  1036.  
  1037.  
  1038. ########################################################################
  1039. #                   Definition of normal Functions
  1040. ########################################################################
  1041. landmark "3: functions";
  1042.  
  1043. ########################################################################
  1044. # abort (<text>*)
  1045. #
  1046. # Unconditionally terminate the program with error code;
  1047. # useful for debugging.
  1048. #
  1049. # defined above
  1050.  
  1051.  
  1052. ########################################################################
  1053. # apropos_run (<name>)
  1054. #
  1055. apropos_run() {
  1056.   func_check apropos_run = 1 "$@";
  1057.   if apropos apropos >/dev/null 2>/dev/null; then
  1058.     apropos "$1";
  1059.   elif man --apropos man >/dev/null 2>/dev/null; then
  1060.     man --apropos "$1";
  1061.   elif man -k man >/dev/null 2>/dev/null; then
  1062.     man -k "$1";
  1063.   fi;
  1064. }
  1065.  
  1066.  
  1067. ########################################################################
  1068. # base_name (<path>)
  1069. #
  1070. # Get the file name part of <path>, i.e. delete everything up to last
  1071. # `/' from the beginning of <path>.  Remove final slashes, too, to get a
  1072. # non-empty output.
  1073. #
  1074. # Arguments : 1
  1075. # Output    : the file name part (without slashes)
  1076. #
  1077. base_name()
  1078. {
  1079.   func_check base_name = 1 "$@";
  1080.   local f;
  1081.   f="$1";
  1082.   case "$f" in
  1083.     */)
  1084.       # delete all final slashes
  1085.       f="$(echo -n "$f" | sed -e '\|//*$|s|||')";
  1086.       ;;
  1087.   esac;
  1088.   case "$f" in
  1089.     /|'')
  1090.       eval "${return_bad}";
  1091.       ;;
  1092.     */*)
  1093.       # delete everything before and including the last slash `/'.
  1094.       echo -n "$f" | sed -e '\|^.*//*\([^/]*\)$|s||\1|';
  1095.       ;;
  1096.     *)
  1097.       echo -n "$f";
  1098.       ;;
  1099.   esac;
  1100.   eval "${return_ok}";
  1101. }
  1102.  
  1103.  
  1104. ########################################################################
  1105. # catz (<file>)
  1106. #
  1107. # Decompress if possible or just print <file> to standard output.
  1108. #
  1109. # gzip, bzip2, and .Z decompression is supported.
  1110. #
  1111. # Arguments: 1, a file name.
  1112. # Output: the content of <file>, possibly decompressed.
  1113. #
  1114. if test "${_HAS_COMPRESSION}" = 'yes'; then
  1115.   catz()
  1116.   {
  1117.     func_check catz = 1 "$@";
  1118.     case "$1" in
  1119.       '')
  1120.         error 'catz(): empty file name';
  1121.         ;;
  1122.       '-')
  1123.         error 'catz(): for standard input use save_stdin()';
  1124.         ;;
  1125.     esac;
  1126.     if obj _HAS_BZIP is_yes; then
  1127.       if bzip2 -t "$1" 2>/dev/null; then
  1128.         bzip2 -c -d "$1" 2>/dev/null;
  1129.         eval "${return_ok}";
  1130.       fi;
  1131.     fi;
  1132.     gzip -c -d -f "$1" 2>/dev/null;
  1133.     eval "${return_ok}";
  1134.   }
  1135. else
  1136.   catz()
  1137.   {
  1138.     func_check catz = 1 "$@";
  1139.     cat "$1";
  1140.     eval "${return_ok}";
  1141.   }
  1142. fi;
  1143.  
  1144.  
  1145. ########################################################################
  1146. # clean_up ()
  1147. #
  1148. # Do the final cleaning up before exiting; used by the trap calls.
  1149. #
  1150. # defined above
  1151.  
  1152.  
  1153. ########################################################################
  1154. # diag (<text>*)
  1155. #
  1156. # Print marked message to standard error; useful for debugging.
  1157. #
  1158. # defined above
  1159.  
  1160.  
  1161. ########################################################################
  1162. landmark '4: dirname()*';
  1163. ########################################################################
  1164.  
  1165. #######################################################################
  1166. # dirname_append (<dir> <name>)
  1167. #
  1168. # Append `name' to `dir' with clean handling of `/'.
  1169. #
  1170. # Arguments : 2
  1171. # Output    : the generated new directory name <dir>/<name>
  1172. #
  1173. dirname_append()
  1174. {
  1175.   func_check dirname_append = 2 "$@";
  1176.   local _res;
  1177.   if is_empty "$1"; then
  1178.     error "dir_append(): first argument is empty.";
  1179.   fi;
  1180.   if is_empty "$2"; then
  1181.     echo -n "$1";
  1182.   else
  1183.     dirname_chop "$1"/"$2";
  1184.   fi;
  1185.   eval "${return_ok}";
  1186. }
  1187.  
  1188.  
  1189. ########################################################################
  1190. # dirname_chop (<name>)
  1191. #
  1192. # Remove unnecessary slashes from directory name.
  1193. #
  1194. # Argument: 1, a directory name.
  1195. # Output:   path without double, or trailing slashes.
  1196. #
  1197. dirname_chop()
  1198. {
  1199.   func_check dirname_chop = 1 "$@";
  1200.   local _arg;
  1201.   local _res;
  1202.   local _sep;
  1203.   # replace all multiple slashes by a single slash `/'.
  1204.   _res="$(echo -n "$1" | sed -e '\|///*|s||/|g')";
  1205.   case "${_res}" in
  1206.     ?*/)
  1207.       # remove trailing slash '/';
  1208.       echo -n "${_res}" | sed -e '\|/$|s|||';
  1209.       ;;
  1210.     *) echo -n "${_res}"; ;;
  1211.   esac;
  1212.   eval "${return_ok}";
  1213. }
  1214.  
  1215.  
  1216. ########################################################################
  1217. # do_filearg (<filearg>)
  1218. #
  1219. # Append the file, man-page, or standard input corresponding to the
  1220. # argument to the temporary file.  If this is compressed in the gzip
  1221. # or Z format it is decompressed.  A title element is generated.
  1222. #
  1223. # Argument either:
  1224. #   - name of an existing files.
  1225. #   - `-' to represent standard input (several times allowed).
  1226. #   - `man:name.(section)' the man-page for `name' in `section'.
  1227. #   - `man:name.section' the man-page for `name' in `section'.
  1228. #   - `man:name' the man-page for `name' in the lowest `section'.
  1229. #   - `name.section' the man-page for `name' in `section'.
  1230. #   - `name' the man-page for `name' in the lowest `section'.
  1231. # Globals :
  1232. #   $_TMP_STDIN, $_MAN_ENABLE, $_MAN_IS_SETUP, $_OPT_MAN
  1233. #
  1234. # Output  : none
  1235. # Return  : $_GOOD if found, ${_BAD} otherwise.
  1236. #
  1237. do_filearg()
  1238. {
  1239.   func_check do_filearg = 1 "$@";
  1240.   local _filespec;
  1241.   local i;
  1242.   _filespec="$1";
  1243.   # store sequence into positional parameters
  1244.   case "${_filespec}" in
  1245.     '')
  1246.        eval "${return_good}";
  1247.        ;;
  1248.     '-')
  1249.       register_file '-';
  1250.       eval "${return_good}";
  1251.       ;;
  1252.     */*)            # with directory part; so no man search
  1253.       set -- 'File';
  1254.       ;;
  1255.     *)
  1256.       if obj _MAN_ENABLE is_yes; then
  1257.         if obj _MAN_FORCE is_yes; then
  1258.           set -- 'Manpage' 'File';
  1259.         else
  1260.           set -- 'File' 'Manpage';
  1261.         fi;
  1262.       else
  1263.         set -- 'File';
  1264.       fi;
  1265.       ;;
  1266.   esac;
  1267.   for i in "$@"; do
  1268.     case "$i" in
  1269.       File)
  1270.         if test -f "${_filespec}"; then
  1271.           if test -r "${_filespec}"; then
  1272.             register_file "${_filespec}";
  1273.             eval "${return_good}";
  1274.           else
  1275.         echo2 "could not read \`${_filespec}'";
  1276.             eval "${return_bad}";
  1277.           fi;
  1278.         else
  1279.           continue;
  1280.         fi;
  1281.         ;;
  1282.       Manpage)            # parse filespec as man page
  1283.         if obj _MAN_IS_SETUP is_not_yes; then
  1284.           man_setup;
  1285.         fi;
  1286.         if man_do_filespec "${_filespec}"; then
  1287.           eval "${return_good}";
  1288.         else
  1289.           continue;
  1290.     fi;
  1291.         ;;
  1292.     esac;
  1293.   done;
  1294.   eval "${return_bad}";
  1295. } # do_filearg()
  1296.  
  1297.  
  1298. ########################################################################
  1299. # do_nothing ()
  1300. #
  1301. # Dummy function.
  1302. #
  1303. do_nothing()
  1304. {
  1305.   return "${_OK}";
  1306. }
  1307.  
  1308.  
  1309. ########################################################################
  1310. # echo2 (<text>*)
  1311. #
  1312. # Print to standard error with final line break.
  1313. #
  1314. # defined above
  1315.  
  1316.  
  1317. ########################################################################
  1318. # echo2n (<text>*)
  1319. #
  1320. # Print to standard error without final line break.
  1321. #
  1322. # defined above
  1323.  
  1324.  
  1325. ########################################################################
  1326. # error (<text>*)
  1327. #
  1328. # Print error message and exit with error code.
  1329. #
  1330. # defined above
  1331.  
  1332.  
  1333. ########################################################################
  1334. # func_check (<func_name> <rel_op> <nr_args> "$@")
  1335. #
  1336. # Check number of arguments and register to _FUNC_STACK.
  1337. #
  1338. # Arguments: >=3
  1339. #   <func_name>: name of the calling function.
  1340. #   <rel_op>:    a relational operator: = != < > <= >= 
  1341. #   <nr_args>:   number of arguments to be checked against <operator>
  1342. #   "$@":        the arguments of the calling function.
  1343. #
  1344. # defined above
  1345.  
  1346. #########################################################################
  1347. # func_pop ()
  1348. #
  1349. # Delete the top element from the function call stack.
  1350. #
  1351. # defined above
  1352.  
  1353.  
  1354. ########################################################################
  1355. # func_push (<element>)
  1356. #
  1357. # Store another element to function call stack.
  1358. #
  1359. # defined above
  1360.  
  1361.  
  1362. ########################################################################
  1363. # func_stack_dump ()
  1364. #
  1365. # Print the content of the stack.
  1366. #
  1367. # defined above
  1368.  
  1369.  
  1370. ########################################################################
  1371. # get_first_essential (<arg>*)
  1372. #
  1373. # Retrieve first non-empty argument.
  1374. #
  1375. # Return  : `1' if all arguments are empty, `0' if found.
  1376. # Output  : the retrieved non-empty argument.
  1377. #
  1378. get_first_essential()
  1379. {
  1380.   func_check get_first_essential '>=' 0 "$@";
  1381.   local i;
  1382.   if is_equal "$#" 0; then
  1383.     eval "${return_ok}";
  1384.   fi;
  1385.   for i in "$@"; do
  1386.     if obj i is_not_empty; then
  1387.       echo -n "$i";
  1388.       eval "${return_ok}";
  1389.     fi;
  1390.   done;
  1391.   eval "${return_bad}";
  1392. }
  1393.  
  1394.  
  1395. ########################################################################
  1396. landmark '5: is_*()';
  1397. ########################################################################
  1398.  
  1399. ########################################################################
  1400. # is_dir (<name>)
  1401. #
  1402. # Test whether `name' is a directory.
  1403. #
  1404. # Arguments : 1
  1405. # Return    : `0' if arg1 is a directory, `1' otherwise.
  1406. #
  1407. is_dir()
  1408. {
  1409.   func_check is_dir = 1 "$@";
  1410.   if test -d "$1" && test -r "$1"; then
  1411.     eval "${return_yes}";
  1412.   fi;
  1413.   eval "${return_no}";
  1414. }
  1415.  
  1416.  
  1417. ########################################################################
  1418. # is_empty (<string>)
  1419. #
  1420. # Test whether `string' is empty.
  1421. #
  1422. # Arguments : <=1
  1423. # Return    : `0' if arg1 is empty or does not exist, `1' otherwise.
  1424. #
  1425. is_empty()
  1426. {
  1427.   func_check is_empty = 1 "$@";
  1428.   if test "$1" = ''; then
  1429.     eval "${return_yes}";
  1430.   fi;
  1431.   eval "${return_no}";
  1432. }
  1433.  
  1434.  
  1435. ########################################################################
  1436. # is_equal (<string1> <string2>)
  1437. #
  1438. # Test whether `string1' is equal to <string2>.
  1439. #
  1440. # Arguments : 2
  1441. # Return    : `0' both arguments are equal strings, `1' otherwise.
  1442. #
  1443. is_equal()
  1444. {
  1445.   func_check is_equal = 2 "$@";
  1446.   if test "$1" = "$2"; then
  1447.     eval "${return_yes}";
  1448.   fi;
  1449.   eval "${return_no}";
  1450. }
  1451.  
  1452.  
  1453. ########################################################################
  1454. # is_file (<name>)
  1455. #
  1456. # Test whether `name' is a readable file.
  1457. #
  1458. # Arguments : 1
  1459. # Return    : `0' if arg1 is a readable file, `1' otherwise.
  1460. #
  1461. is_file()
  1462. {
  1463.   func_check is_file = 1 "$@";
  1464.   if test -f "$1" && test -r "$1"; then
  1465.     eval "${return_yes}";
  1466.   fi;
  1467.   eval "${return_no}";
  1468. }
  1469.  
  1470.  
  1471. ########################################################################
  1472. # is_non_empty_file (<file_name>)
  1473. #
  1474. # Test whether `file_name' is a non-empty existing file.
  1475. #
  1476. # Arguments : <=1
  1477. # Return    :
  1478. #   `0' if arg1 is a non-empty existing file
  1479. #   `1' otherwise
  1480. #
  1481. is_non_empty_file()
  1482. {
  1483.   func_check is_empty = 1 "$@";
  1484.   if is_file "$1"; then
  1485.     if is_not_empty "$(cat "$1" | sed -e '/./q')"; then
  1486.       eval "${return_yes}";
  1487.     fi;
  1488.   fi;
  1489.   eval "${return_no}";
  1490. }
  1491.  
  1492.  
  1493. ########################################################################
  1494. # is_not_dir (<name>)
  1495. #
  1496. # Test whether `name' is not a readable directory.
  1497. #
  1498. # Arguments : 1
  1499. # Return    : `0' if arg1 is a directory, `1' otherwise.
  1500. #
  1501. is_not_dir()
  1502. {
  1503.   func_check is_not_dir = 1 "$@";
  1504.   if is_dir "$1"; then
  1505.     eval "${return_no}";
  1506.   fi;
  1507.   eval "${return_yes}";
  1508. }
  1509.  
  1510.  
  1511. ########################################################################
  1512. # is_not_empty (<string>)
  1513. #
  1514. # Test whether `string' is not empty.
  1515. #
  1516. # Arguments : <=1
  1517. # Return    : `0' if arg1 exists and is not empty, `1' otherwise.
  1518. #
  1519. is_not_empty()
  1520. {
  1521.   func_check is_not_empty = 1 "$@";
  1522.   if is_empty "$1"; then
  1523.     eval "${return_no}";
  1524.   fi;
  1525.   eval "${return_yes}";
  1526. }
  1527.  
  1528.  
  1529. ########################################################################
  1530. # is_not_equal (<string1> <string2>)
  1531. #
  1532. # Test whether `string1' differs from `string2'.
  1533. #
  1534. # Arguments : 2
  1535. #
  1536. is_not_equal()
  1537. {
  1538.   func_check is_not_equal = 2 "$@";
  1539.   if is_equal "$1" "$2"; then
  1540.     eval "${return_no}";
  1541.   fi
  1542.   eval "${return_yes}";
  1543. }
  1544.  
  1545.  
  1546. ########################################################################
  1547. # is_not_file (<filename>)
  1548. #
  1549. # Test whether `name' is a not readable file.
  1550. #
  1551. # Arguments : >=1 (empty allowed), more args are ignored
  1552. #
  1553. is_not_file()
  1554. {
  1555.   func_check is_not_file '>=' 1 "$@";
  1556.   if is_file "$1"; then
  1557.     eval "${return_no}";
  1558.   fi;
  1559.   eval "${return_yes}";
  1560. }
  1561.  
  1562.  
  1563. ########################################################################
  1564. # is_not_prog (<name>)
  1565. #
  1566. # Verify that arg is a not program in $PATH.
  1567. #
  1568. # Arguments : >=1 (empty allowed)
  1569. #   more args are ignored, this allows to specify progs with arguments
  1570. #
  1571. is_not_prog()
  1572. {
  1573.   func_check is_not_prog '>=' 1 "$@";
  1574.   if where "$1" >/dev/null; then
  1575.     eval "${return_no}";
  1576.   fi;
  1577.   eval "${return_yes}";
  1578. }
  1579.  
  1580.  
  1581. ########################################################################
  1582. # is_not_writable (<name>)
  1583. #
  1584. # Test whether `name' is a not a writable file or directory.
  1585. #
  1586. # Arguments : >=1 (empty allowed), more args are ignored
  1587. #
  1588. is_not_writable()
  1589. {
  1590.   func_check is_not_writable '>=' 1 "$@";
  1591.   if is_writable "$1"; then
  1592.     eval "${return_no}";
  1593.   fi;
  1594.   eval "${return_yes}";
  1595. }
  1596.  
  1597.  
  1598. ########################################################################
  1599. # is_not_yes (<string>)
  1600. #
  1601. # Test whether `string' is not "yes".
  1602. #
  1603. # Arguments : 1
  1604. #
  1605. is_not_yes()
  1606. {
  1607.   func_check is_not_yes = 1 "$@";
  1608.   if is_yes "$1"; then
  1609.     eval "${return_no}";
  1610.   fi;
  1611.   eval "${return_yes}";
  1612. }
  1613.  
  1614.  
  1615. ########################################################################
  1616. # is_prog (<name>)
  1617. #
  1618. # Determine whether arg is a program in $PATH
  1619. #
  1620. # Arguments : >=0 (empty allowed)
  1621. #   more args are ignored, this allows to specify progs with arguments
  1622. #
  1623. is_prog()
  1624. {
  1625.   func_check is_prog '>=' 0 "$@";
  1626.   case "$#" in
  1627.   0)
  1628.     eval "${return_no}";
  1629.     ;;
  1630.   *)
  1631.     if where "$1" >/dev/null; then
  1632.       eval "${return_yes}";
  1633.     fi;
  1634.     ;;
  1635.   esac
  1636.   eval "${return_no}";
  1637. }
  1638.  
  1639.  
  1640. ########################################################################
  1641. # is_writable (<name>)
  1642. #
  1643. # Test whether `name' is a writable file or directory.
  1644. #
  1645. # Arguments : >=1 (empty allowed), more args are ignored
  1646. #
  1647. is_writable()
  1648. {
  1649.   func_check is_writable '>=' 1 "$@";
  1650.   if test -r "$1"; then
  1651.     if test -w "$1"; then
  1652.       eval "${return_yes}";
  1653.     fi;
  1654.   fi;
  1655.   eval "${return_no}";
  1656. }
  1657.  
  1658.  
  1659. ########################################################################
  1660. # is_yes (<string>)
  1661. #
  1662. # Test whether `string' has value "yes".
  1663. #
  1664. # Arguments : <=1
  1665. # Return    : `0' if arg1 is `yes', `1' otherwise.
  1666. #
  1667. is_yes()
  1668. {
  1669.   func_check is_yes = 1 "$@";
  1670.   if is_equal "$1" 'yes'; then
  1671.     eval "${return_yes}";
  1672.   fi;
  1673.   eval "${return_no}";
  1674. }
  1675.  
  1676.  
  1677. ########################################################################
  1678. # landmark ()
  1679. #
  1680. # Print debugging information on standard error if $_DEBUG_LM is `yes'.
  1681. #
  1682. # Globals: $_DEBUG_LM
  1683. #
  1684. # Defined in section `Debugging functions'.
  1685.  
  1686.  
  1687. ########################################################################
  1688. # leave ()
  1689. #
  1690. # Clean exit without an error.
  1691. #
  1692. leave()
  1693. {
  1694.   clean_up;
  1695.   exit "${_OK}";
  1696. }
  1697.  
  1698.  
  1699. ########################################################################
  1700. landmark '6: list_*()';
  1701. ########################################################################
  1702. #
  1703. # `list' is an object class that represents an array or list.  Its
  1704. # data consists of space-separated single-quoted elements.  So a list
  1705. # has the form "'first' 'second' '...' 'last'".  See list_append() for
  1706. # more details on the list structure.  The array elements of `list'
  1707. # can be get by `set -- $list`.
  1708.  
  1709.  
  1710. ########################################################################
  1711. # list_append (<list> <element>...)
  1712. #
  1713. # Arguments: >=2
  1714. #   <list>: a variable name for a list of single-quoted elements
  1715. #   <element>:  some sequence of characters.
  1716. # Output: none, but $<list> is set to
  1717. #   if <list> is empty:  "'<element>' '...'"
  1718. #   otherwise:           "$list '<element>' ..."
  1719. #
  1720. list_append()
  1721. {
  1722.   func_check list_append '>=' 2 "$@";
  1723.   local _element;
  1724.   local _list;
  1725.   local _name;
  1726.   _name="$1";
  1727.   eval _list='"${'$1'}"';
  1728.   shift;
  1729.   for s in "$@"; do
  1730.     case "$s" in
  1731.     *\'*)
  1732.       # escape each single quote by replacing each
  1733.       # "'" (squote) by "'\''" (squote bslash squote squote);
  1734.       # note that the backslash must be doubled in the following `sed'
  1735.       _element="$(echo -n "$s" | sed -e 's/'"${_SQUOTE}"'/&\\&&/g')";
  1736.       ;;
  1737.     '')  
  1738.       _element="";
  1739.       ;;
  1740.     *)
  1741.       _element="$s";
  1742.       ;;
  1743.     esac;
  1744.     if obj _list is_empty; then
  1745.       _list="'${_element}'";
  1746.     else
  1747.       _list="${_list} '${_element}'";
  1748.     fi;
  1749.   done;
  1750.   eval "${_name}"='"${_list}"';
  1751.   eval "${return_ok}";
  1752. }
  1753.  
  1754.  
  1755. ########################################################################
  1756. # list_from_cmdline (<s_n> <s_a> <l_n> <l_a> [<cmdline_arg>...])
  1757. #
  1758. # Transform command line arguments into a normalized form.
  1759. #
  1760. # Options, option arguments, and file parameters are identified and
  1761. # output each as a single-quoted argument of its own.  Options and
  1762. # file parameters are separated by a '--' argument.
  1763. #
  1764. # Arguments: >=4
  1765. #   <s_n>: space-separated list of short options without an arg.
  1766. #   <s_a>: space-separated list of short options that have an arg.
  1767. #   <l_n>: space-separated list of long options without an arg.
  1768. #   <l_a>: space-separated list of long options that have an arg.
  1769. #   <cmdline_arg>...: the arguments from a command line, such as "$@",
  1770. #                     the content of a variable, or direct arguments.
  1771. #
  1772. # Globals: $POSIXLY_CORRECT (only kept for compatibility).
  1773. #
  1774. # Output: ['-[-]opt' ['optarg']]... '--' ['filename']...
  1775. #
  1776. # Example:
  1777. #     list_normalize 'a b' 'c' '' 'long' -a f1 -bcarg --long=larg f2
  1778. #   will result in printing:
  1779. #     '-a' '-b' '-c' 'arg' '--long' 'larg' '--' 'f1' 'f2'
  1780. #   If $POSIXLY_CORRECT is not empty, the result will be:
  1781. #     '-a' '--' 'f1' '-bcarg' '--long=larg' 'f2'
  1782. #
  1783. #   Rationale:
  1784. #     In POSIX, the first non-option ends the option processing.
  1785. #     In GNU mode, used by default, non-option arguments are sorted
  1786. #     behind the options.
  1787. #
  1788. #   Use this function only in the following way:
  1789. #     eval set -- "$(args_norm '...' '...' '...' '...' "$@")";
  1790. #     while test "$1" != '--'; do
  1791. #       case "$1" in
  1792. #       ...
  1793. #       esac;
  1794. #       shift;
  1795. #     done;
  1796. #     shift;         #skip '--'
  1797. #     # all positional parameters ("$@") left are file name parameters.
  1798. #
  1799. list_from_cmdline()
  1800. {
  1801.   func_check list_from_cmdline '>=' 4 "$@";
  1802.   local _fparams;
  1803.   local _fn;
  1804.   local _result;
  1805.   local _long_a;
  1806.   local _long_n;
  1807.   local _short_a;
  1808.   local _short_n;
  1809.   _short_n="$(list_get "$1")"; # short options, no argument
  1810.   _short_a="$(list_get "$2")"; # short options with argument
  1811.   _long_n="$(list_get "$3")";     # long options, no argument
  1812.   _long_a="$(list_get "$4")";     # long options with argument
  1813.   shift 4;
  1814.   _fn='list_from_cmdline():';     # for error messages
  1815.   if is_equal "$#" 0; then
  1816.     echo -n "'--'";
  1817.     eval "${return_ok}";
  1818.   fi;
  1819.   _fparams='';
  1820.   _result='';
  1821.   while test "$#" -ge 1; do
  1822.     _arg="$1";
  1823.     shift;
  1824.     case "$_arg" in
  1825.       --) break; ;;
  1826.       --?*)
  1827.         # delete leading '--';
  1828.         _opt="$(echo -n "${_arg}" | sed -e 's/^..//')";
  1829.         if list_has _long_n "${_opt}"; then
  1830.           # long option, no argument
  1831.           list_append _result "--${_opt}";
  1832.           continue;
  1833.         fi;
  1834.         # test on `--opt=arg'
  1835.         if string_contains "${_opt}" '='; then
  1836.           # extract option by deleting from the first '=' to the end
  1837.           _lopt="$(echo -n "${_opt}" | sed -e 's/=.*$//')";
  1838.           if list_has _long_a "${_lopt}"; then
  1839.             # get the option argument by deleting up to first `='
  1840.             _optarg="$(echo -n "${_opt}" | sed -e 's/^[^=]*=//')";
  1841.             list_append _result "--${_lopt}" "${_optarg}";
  1842.             continue;
  1843.           fi;
  1844.         fi;
  1845.         if list_has _long_a "${_opt}"; then
  1846.           # long option with argument
  1847.           if test "$#" -le 0; then
  1848.             error "${_fn} no argument for option --${_opt}."
  1849.           fi;
  1850.           list_append _result "--${_opt}" "$1";
  1851.           shift;
  1852.           continue;
  1853.         fi;
  1854.         error "${_fn} --${_opt} is not an option."
  1855.         ;;
  1856.       -?*)            # short option (cluster)
  1857.         # delete leading `-';
  1858.         _rest="$(echo -n "${_arg}" | sed -e 's/^-//')";
  1859.         while obj _rest is_not_empty; do
  1860.           # get next short option from cluster (first char of $_rest)
  1861.           _optchar="$(echo -n "${_rest}" | sed -e 's/^\(.\).*$/\1/')";
  1862.           # remove first character from ${_rest};
  1863.           _rest="$(echo -n "${_rest}" | sed -e 's/^.//')";
  1864.           if list_has _short_n "${_optchar}"; then
  1865.             list_append _result "-${_optchar}";
  1866.             continue;
  1867.           elif list_has _short_a "${_optchar}"; then
  1868.             if obj _rest is_empty; then
  1869.               if test "$#" -ge 1; then
  1870.                 list_append _result "-${_optchar}" "$1";
  1871.                 shift;
  1872.                 continue;
  1873.               else
  1874.                 error \
  1875.                   "${_fn}"' no argument for option -'"${_optchar}."
  1876.               fi;
  1877.             else        # rest is the argument
  1878.               list_append _result "-${_optchar}" "${_rest}";
  1879.               _rest='';
  1880.               continue;
  1881.             fi;
  1882.           else
  1883.             error "${_fn} unknown option -${_optchar}."
  1884.           fi;
  1885.         done;
  1886.         ;;
  1887.       *)
  1888.     # Here, $_arg is not an option, so a file parameter.
  1889.         # When $POSIXLY_CORRECT is set this ends option parsing;
  1890.         # otherwise, the argument is stored as a file parameter and
  1891.         # option processing is continued.
  1892.         list_append _fparams "${_arg}";
  1893.     if obj POSIXLY_CORRECT is_not_empty; then
  1894.           break;
  1895.         fi;
  1896.         ;;
  1897.     esac;
  1898.   done;
  1899.   list_append _result '--';
  1900.   if obj _fparams is_not_empty; then
  1901.     _result="${_result} ${_fparams}";
  1902.   fi;
  1903.   if test "$#" -gt 0; then
  1904.     list_append _result "$@";
  1905.   fi;
  1906.   echo -n "$_result";
  1907.   eval "${return_ok}";
  1908. } # list_from_cmdline()
  1909.  
  1910.  
  1911. ########################################################################
  1912. # list_from_split (<string> <separator>)
  1913. #
  1914. # In <string>, escape all white space characters and replace each
  1915. # <separator> by space.
  1916. #
  1917. # Arguments: 2: a <string> that is to be split into parts divided by
  1918. #               <separator>
  1919. # Output:    the resulting list string
  1920. #
  1921. list_from_split()
  1922. {
  1923.   func_check list_from_split = 2 "$@";
  1924.   local _s;
  1925.  
  1926.   # precede each space or tab by a backslash `\' (doubled for `sed')
  1927.   _s="$(echo -n "$1" | sed -e 's/\(['"${_SPACE}${_TAB}"']\)/\\\1/g')";
  1928.  
  1929.   # replace split character of string by the list separator ` ' (space).
  1930.   case "$2" in
  1931.     /)                # cannot use normal `sed' separator
  1932.       echo -n "${_s}" | sed -e '\|'"$2"'|s|| |g';
  1933.       ;;
  1934.     ?)                # use normal `sed' separator
  1935.       echo -n "${_s}" | sed -e 's/'"$2"'/ /g';
  1936.       ;;
  1937.     ??*)
  1938.       error 'list_from_split(): separator must be a single character.';
  1939.       ;;
  1940.   esac;
  1941.   eval "${return_ok}";
  1942. }
  1943.  
  1944.  
  1945. ########################################################################
  1946. # list_get (<list>)
  1947. #
  1948. # Check whether <list> is a space-separated list of '-quoted elements.
  1949. #
  1950. # If the test fails an error is raised.
  1951. # If the test succeeds the argument is echoed.
  1952. #
  1953. # Testing criteria:
  1954. #   A list has the form "'first' 'second' '...' 'last'".  So it has a
  1955. #   leading and a final quote and the elements are separated by "' '"
  1956. #   constructs.  If these are all removed there should not be any
  1957. #   unescaped single-quotes left.  Watch out for escaped single
  1958. #   quotes; they have the form '\'' (sq bs sq sq).
  1959.  
  1960. # Arguments: 1
  1961. # Output: the argument <list> unchanged, if the check succeeded.
  1962. #
  1963. list_get()
  1964. {
  1965.   func_check list_get = 1 "$@";
  1966.   local _list;
  1967.   eval _list='"${'$1'}"';
  1968.   # remove leading and final space characters
  1969.   _list="$(echo -n "${_list}" | \
  1970.            sed -e '/^['"${_SPACE}${_TAB}"']*/s///' | \
  1971.            sed -e '/['"${_SPACE}${_TAB}"']*$/s///')";
  1972.   case "${_list}" in
  1973.   '')
  1974.     eval "${return_ok}";
  1975.     ;;
  1976.   \'*\')
  1977.     echo -n "${_list}";
  1978.     eval "${return_ok}";
  1979.     ;;
  1980.   *)
  1981.     error "list_get(): bad list: $1"
  1982.     ;;
  1983.   esac;
  1984.   eval "${return_ok}";
  1985. }
  1986.  
  1987.  
  1988. ########################################################################
  1989. # list_has (<var_name> <element>)
  1990. #
  1991. # Arguments: 2
  1992. #   <var_name>: a variable name for a list of single-quoted elements
  1993. #   <element>:  some sequence of characters.
  1994. # Output:
  1995. #   if <list> is empty:  "'<element>' '...'"
  1996. #   otherwise:           "list '<element>' ..."
  1997. #
  1998. list_has()
  1999. {
  2000.   func_check list_has = 2 "$@";
  2001.   eval _list='"${'$1'}"';
  2002.   if obj _list is_empty; then
  2003.     eval "${return_no}";
  2004.   fi;
  2005.   _element="$2";
  2006.   case "$2" in
  2007.     \'*\')  _element="$2"; ;;
  2008.     *)      _element="'$2'"; ;;
  2009.   esac;
  2010.   if string_contains "${_list}" "${_element}"; then
  2011.     eval "${return_yes}";
  2012.   else
  2013.     eval "${return_no}";
  2014.   fi;
  2015.   eval "${return_ok}";
  2016. }
  2017.  
  2018.  
  2019. ########################################################################
  2020. # list_has_not (<list> <element>)
  2021. #
  2022. # Arguments: 2
  2023. #   <list>:    a space-separated list of single-quoted elements.
  2024. #   <element>: some sequence of characters.
  2025. # Output:
  2026. #   if <list> is empty:  "'<element>' '...'"
  2027. #   otherwise:           "<list> '<element>' ..."
  2028. #
  2029. list_has_not()
  2030. {
  2031.   func_check list_has_not = 2 "$@";
  2032.   eval _list='"${'$1'}"';
  2033.   if obj _list is_empty; then
  2034.     eval "${return_yes}";
  2035.   fi;
  2036.   _element="$2";
  2037.   case "$2" in
  2038.     \'*\')  _element="$2"; ;;
  2039.     *)      _element="'$2'"; ;;
  2040.   esac;
  2041.   if string_contains "${_list}" "${_element}"; then
  2042.     eval "${return_no}";
  2043.   else
  2044.     eval "${return_yes}";
  2045.   fi;
  2046.   eval "${return_ok}";
  2047. }
  2048.  
  2049.  
  2050. ########################################################################
  2051. landmark '7: man_*()';
  2052. ########################################################################
  2053.  
  2054. ########################################################################
  2055. # man_do_filespec (<filespec>)
  2056. #
  2057. # Print suitable man page(s) for filespec to $_TMP_CAT.
  2058. #
  2059. # Arguments : 2
  2060. #   <filespec>: argument of the form `man:name.section', `man:name',
  2061. #               `man:name(section)', `name.section', `name'.
  2062. #
  2063. # Globals   : $_OPT_ALL
  2064. #
  2065. # Output    : none.
  2066. # Return    : `0' if man page was found, `1' else.
  2067. #
  2068. # Only called from do_fileargs(), checks on $MANPATH and
  2069. # $_MAN_ENABLE are assumed.
  2070. #
  2071. man_do_filespec()
  2072. {
  2073.   func_check man_do_filespec = 1 "$@";
  2074.   local _got_one;
  2075.   local _name;
  2076.   local _prevsec;
  2077.   local _res;
  2078.   local _section;
  2079.   local _spec;
  2080.   local _string;
  2081.   local s;
  2082.   if obj _MAN_PATH is_empty; then
  2083.     eval "${return_bad}";
  2084.   fi;
  2085.   if is_empty "$1"; then
  2086.     eval "${return_bad}";
  2087.   fi;
  2088.   _spec="$1";
  2089.   _name='';
  2090.   _section='';
  2091.   case "${_spec}" in
  2092.     */*)            # not a man spec when it contains '/'
  2093.       eval "${return_bad}";
  2094.       ;;
  2095.     man:?*\(?*\))        # man:name(section)
  2096.       _name="$(echo -n "${_spec}" \
  2097.                | sed -e 's/^man:\(..*\)(\(..*\))$/\1/')";
  2098.       _section="$(echo -n "${_spec}" \
  2099.                | sed -e 's/^man:\(..*\)(\(..*\))$/\2/')";
  2100.       ;;
  2101.     man:?*.[0-9on])            # man:name.section
  2102.       _name="$(echo -n "${_spec}" \
  2103.                | sed -e 's/^man:\(..*\)\..$/\1/')";
  2104.       _section="$(echo -n "${_spec}" \
  2105.                | sed -e 's/^.*\(.\)$/\1/')";
  2106.       ;;
  2107.     man:?*)            # man:name
  2108.       _name="$(echo -n "${_spec}" | sed -e 's/^man://')";
  2109.       ;;
  2110.     ?*\(?*\))            # name(section)
  2111.       _name="$(echo -n "${_spec}" \
  2112.                | sed -e 's/^\(..*\)(\(..*\))$/\1/')";
  2113.       _section="$(echo -n "${_spec}" \
  2114.                | sed -e 's/^\(..*\)(\(..*\))$/\2/')";
  2115.       ;;
  2116.     ?*.[0-9on])            # name.section
  2117.       _name="$(echo -n "${_spec}" \
  2118.                | sed -e 's/^\(..*\)\..$/\1/')";
  2119.       _section="$(echo -n "${_spec}" \
  2120.                | sed -e 's/^.*\(.\)$/\1/')";
  2121.       ;;
  2122.     ?*)
  2123.       _name="${_filespec}";
  2124.       ;;
  2125.   esac;
  2126.   if obj _name is_empty; then
  2127.     eval "${return_bad}";
  2128.   fi;
  2129.   _got_one='no';
  2130.   if obj _section is_empty; then
  2131.     eval set -- "${_MAN_AUTO_SEC}";
  2132.     for s in "$@"; do
  2133.       if man_search_section "${_name}" "$s"; then # found
  2134.         if obj _MAN_ALL is_yes; then
  2135.           _got_one='yes';
  2136.         else
  2137.           eval "${return_good}";
  2138.         fi;
  2139.       fi;
  2140.     done;
  2141.   else
  2142.     if man_search_section "${_name}" "${_section}"; then
  2143.       eval "${return_good}";
  2144.     else
  2145.       eval "${return_bad}";
  2146.     fi;
  2147.   fi;
  2148.   if obj _MAN_ALL is_yes && is_yes "${_got_one}"; then
  2149.     eval "${return_good}";
  2150.   fi;
  2151.   eval "${return_bad}";
  2152. } # man_do_filespec()
  2153.  
  2154.  
  2155. ########################################################################
  2156. # man_register_file (<file> <name> [<section>])
  2157. #
  2158. # Write a found man page file and register the title element.
  2159. #
  2160. # Arguments: 1, 2, or 3; maybe empty
  2161. # Output: none
  2162. #
  2163. man_register_file()
  2164. {
  2165.   func_check man_register_file '>=' 2 "$@";
  2166.   case "$#" in
  2167.     2|3) do_nothing; ;;
  2168.     *)
  2169.       error "man_register_file() expects 2 or 3 arguments.";
  2170.       ;;
  2171.   esac;
  2172.   if is_empty "$1"; then
  2173.     error 'man_register_file(): file name is empty';
  2174.   fi;
  2175.   to_tmp "$1";
  2176.   case "$#" in
  2177.     2)
  2178.        register_title "man:$2";
  2179.        eval "${return_ok}";
  2180.        ;;
  2181.     3)
  2182.        register_title "$2.$3";
  2183.        eval "${return_ok}";
  2184.        ;;
  2185.   esac;
  2186.   eval "${return_ok}";
  2187. }
  2188.  
  2189.  
  2190. ########################################################################
  2191. # man_search_section (<name> <section>)
  2192. #
  2193. # Retrieve man pages.
  2194. #
  2195. # Arguments : 2
  2196. # Globals   : $_MAN_PATH, $_MAN_EXT
  2197. # Return    : 0 if found, 1 otherwise
  2198. #
  2199. man_search_section()
  2200. {
  2201.   func_check man_search_section = 2 "$@";
  2202.   local _dir;
  2203.   local _ext;
  2204.   local _got_one;
  2205.   local _name;
  2206.   local _prefix
  2207.   local _section;
  2208.   local d;
  2209.   local f;
  2210.   if obj _MAN_PATH is_empty; then
  2211.     eval "${return_bad}";
  2212.   fi;
  2213.   if is_empty "$1"; then
  2214.     eval "${return_bad}";
  2215.   fi;
  2216.   if is_empty "$2"; then
  2217.     eval "${return_bad}";
  2218.   fi;
  2219.   _name="$1";
  2220.   _section="$2";
  2221.   eval set -- "$(path_split "${_MAN_PATH}")";
  2222.   _got_one='no';
  2223.   if obj _MAN_EXT is_empty; then
  2224.     for d in "$@"; do
  2225.       _dir="$(dirname_append "$d" "man${_section}")";
  2226.       if obj _dir is_dir; then
  2227.         _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
  2228.         for f in $(echo -n ${_prefix}*); do
  2229.           if obj f is_file; then
  2230.             if is_yes "${_got_one}"; then
  2231.               register_file "$f";
  2232.             elif obj _MAN_ALL is_yes; then
  2233.               man_register_file "$f" "${_name}";
  2234.             else
  2235.               man_register_file "$f" "${_name}" "${_section}";
  2236.               eval "${return_good}";
  2237.             fi;
  2238.             _got_one='yes';
  2239.           fi;
  2240.         done;
  2241.       fi;
  2242.     done;
  2243.   else
  2244.     _ext="${_MAN_EXT}";
  2245.     # check for directory name having trailing extension
  2246.     for d in "$@"; do
  2247.       _dir="$(dirname_append $d man${_section}${_ext})";
  2248.       if obj _dir is_dir; then
  2249.         _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
  2250.         for f in ${_prefix}*; do
  2251.           if obj f is_file; then
  2252.             if is_yes "${_got_one}"; then
  2253.               register_file "$f";
  2254.             elif obj _MAN_ALL is_yes; then
  2255.               man_register_file "$f" "${_name}";
  2256.             else
  2257.               man_register_file "$f" "${_name}" "${_section}";
  2258.               eval "${return_good}";
  2259.             fi;
  2260.             _got_one='yes';
  2261.           fi;
  2262.         done;
  2263.       fi;
  2264.     done;
  2265.     # check for files with extension in directories without extension
  2266.     for d in "$@"; do
  2267.       _dir="$(dirname_append "$d" "man${_section}")";
  2268.       if obj _dir is_dir; then
  2269.         _prefix="$(dirname_append "${_dir}" \
  2270.                                   "${_name}.${_section}${_ext}")";
  2271.         for f in ${_prefix}*; do
  2272.           if obj f is_file; then
  2273.             if is_yes "${_got_one}"; then
  2274.               register_file "$f";
  2275.             elif obj _MAN_ALL is_yes; then
  2276.               man_register_file "$f" "${_name}";
  2277.             else
  2278.               man_register_file "$f" "${_name}" "${_section}";
  2279.               eval "${return_good}";
  2280.             fi;
  2281.             _got_one='yes';
  2282.           fi;
  2283.         done;
  2284.       fi;
  2285.     done;
  2286.   fi;
  2287.   if obj _MAN_ALL is_yes && is_yes "${_got_one}"; then
  2288.     eval "${return_good}";
  2289.   fi;
  2290.   eval "${return_bad}";
  2291. } # man_search_section()
  2292.  
  2293.  
  2294. ########################################################################
  2295. # man_setup ()
  2296. #
  2297. # Setup the variables $_MAN_* needed for man page searching.
  2298. #
  2299. # Globals:
  2300. #   in:     $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL,
  2301. #           $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM, $MANOPT.
  2302. #   out:    $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2,
  2303. #           $_MAN_SEC, $_MAN_ALL
  2304. #   in/out: $_MAN_ENABLE
  2305. #
  2306. # The precedence for the variables related to `man' is that of GNU
  2307. # `man', i.e.
  2308. #
  2309. # $LANG; overridden by
  2310. # $LC_MESSAGES; overridden by
  2311. # $LC_ALL; this has the same precedence as
  2312. # $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM; overridden by
  2313. # $MANOPT; overridden by
  2314. # the groffer command line options.
  2315. #
  2316. man_setup()
  2317. {
  2318.   func_check main_man_setup = 0 "$@";
  2319.   local _lang;
  2320.  
  2321.   if obj _MAN_IS_SETUP is_yes; then
  2322.     eval "${return_ok}";
  2323.   fi;
  2324.   _MAN_IS_SETUP='yes';
  2325.  
  2326.   if obj _MAN_ENABLE is_not_yes; then
  2327.     eval "${return_ok}";
  2328.   fi;
  2329.  
  2330.   # determine basic path for man pages
  2331.   _MAN_PATH="$(get_first_essential \
  2332.                "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}")";
  2333.   if obj _MAN_PATH is_empty; then
  2334.     manpath_set_from_path;
  2335.   else
  2336.     _MAN_PATH="$(path_clean "${_MAN_PATH}")";
  2337.   fi;
  2338.   if obj _MAN_PATH is_empty; then
  2339.     if is_prog 'manpath'; then
  2340.       _MAN_PATH="$(manpath 2>/dev/null)"; # not always available
  2341.     fi;
  2342.   fi;
  2343.   if obj _MAN_PATH is_empty; then
  2344.     _MAN_ENABLE="no";
  2345.     eval "${return_ok}";
  2346.   fi;
  2347.  
  2348.   _MAN_ALL="$(get_first_essential "${_OPT_ALL}" "${_MANOPT_ALL}")";
  2349.   if obj _MAN_ALL is_empty; then
  2350.     _MAN_ALL='no';
  2351.   fi;
  2352.  
  2353.   _MAN_SYS="$(get_first_essential \
  2354.               "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")";
  2355.   _lang="$(get_first_essential \
  2356.            "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}")";
  2357.   case "${_lang}" in
  2358.     C|POSIX)
  2359.       _MAN_LANG="";
  2360.       _MAN_LANG2="";
  2361.       ;;
  2362.     ?)
  2363.       _MAN_LANG="${_lang}";
  2364.       _MAN_LANG2="";
  2365.       ;;
  2366.     *)
  2367.       _MAN_LANG="${_lang}";
  2368.       # get first two characters of $_lang
  2369.       _MAN_LANG2="$(echo -n "${_lang}" | sed -e 's/^\(..\).*$/\1/')";
  2370.       ;;
  2371.   esac;
  2372.   # from now on, use only $_LANG, forget about $_OPT_LANG, $LC_*.
  2373.  
  2374.   manpath_add_lang_sys;        # this is very slow
  2375.  
  2376.   _MAN_SEC="$(get_first_essential \
  2377.               "${_OPT_SECT}" "${_MANOPT_SEC}" "${MANSEC}")";
  2378.   if obj _MAN_PATH is_empty; then
  2379.     _MAN_ENABLE="no";
  2380.     eval "${return_ok}";
  2381.   fi;
  2382.  
  2383.   _MAN_EXT="$(get_first_essential \
  2384.               "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}")";
  2385.   eval "${return_ok}";
  2386. } # man_setup()
  2387.  
  2388.  
  2389. ########################################################################
  2390. landmark '8: manpath_*()';
  2391. ########################################################################
  2392.  
  2393. ########################################################################
  2394. # manpath_add_lang_sys ()
  2395. #
  2396. # Add language and operating system specific directories to man path.
  2397. #
  2398. # Arguments : 0
  2399. # Output    : none
  2400. # Globals:
  2401. #   in:     $_MAN_SYS: has the form `os1,os2,...', a comma separated
  2402. #             list of names of operating systems.
  2403. #           $_MAN_LANG and $_MAN_LANG2: each a single name
  2404. #   in/out: $_MAN_PATH: has the form `dir1:dir2:...', a colon
  2405. #             separated list of directories.
  2406. #
  2407. manpath_add_lang_sys()
  2408. {
  2409.   func_check manpath_add_lang_sys = 0 "$@";
  2410.   local p;
  2411.   local _mp;
  2412.   if obj _MAN_PATH is_empty; then
  2413.     eval "${return_ok}";
  2414.   fi;
  2415.   # twice test both sys and lang
  2416.   eval set -- "$(path_split "${_MAN_PATH}")";
  2417.   _mp='';
  2418.   for p in "$@"; do        # loop on man path directories
  2419.     _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
  2420.   done;
  2421.   eval set -- "$(path_split "${_mp}")";
  2422.   for p in "$@"; do        # loop on man path directories
  2423.     _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
  2424.   done;
  2425.   _MAN_PATH="$(path_chop "${_mp}")";
  2426.   eval "${return_ok}";
  2427. }
  2428.  
  2429.  
  2430. _manpath_add_lang_sys_single()
  2431. {
  2432.   # To the directory in $1 append existing sys/lang subdirectories
  2433.   # Function is necessary to split the OS list.
  2434.   #
  2435.   # globals: in: $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2
  2436.   # argument: 2: `man_path' and `dir'
  2437.   # output: colon-separated path of the retrieved subdirectories
  2438.   #
  2439.   func_check _manpath_add_lang_sys_single = 2 "$@";
  2440.   local d;
  2441.   _res="$1";
  2442.   _parent="$2";
  2443.   eval set -- "$(list_from_split "${_MAN_SYS}" ',')";
  2444.   for d in "$@" "${_MAN_LANG}" "${_MAN_LANG2}"; do
  2445.     _dir="$(dirname_append "${_parent}" "$d")";
  2446.     if obj _res path_not_contains "${_dir}" && obj _dir is_dir; then
  2447.       _res="${_res}:${_dir}";
  2448.     fi;
  2449.   done;
  2450.   if path_not_contains "${_res}" "${_parent}"; then
  2451.     _res="${_res}:${_parent}";
  2452.   fi;
  2453.   path_chop "${_res}";
  2454. }
  2455.  
  2456. # end manpath_add_lang_sys ()
  2457.  
  2458.  
  2459. ########################################################################
  2460. # manpath_set_from_path ()
  2461. #
  2462. # Determine basic search path for man pages from $PATH.
  2463. #
  2464. # Return:    `0' if a valid man path was retrieved.
  2465. # Output:    none
  2466. # Globals:
  2467. #   in:  $PATH
  2468. #   out: $_MAN_PATH
  2469. #
  2470. manpath_set_from_path()
  2471. {
  2472.   func_check manpath_set_from_path = 0 "$@";
  2473.   local _base;
  2474.   local _mandir;
  2475.   local _manpath;
  2476.   local d;
  2477.   local e;
  2478.   _manpath='';
  2479.  
  2480.   # get a basic man path from $PATH
  2481.   if obj PATH is_not_empty; then
  2482.     eval set -- "$(path_split "${PATH}")";
  2483.     for d in "$@"; do
  2484.       # delete the final `/bin' part
  2485.       _base="$(echo -n "$d" | sed -e '\|//*bin/*$|s|||')";
  2486.       for e in /share/man /man; do
  2487.         _mandir="${_base}$e";
  2488.         if test -d "${_mandir}" && test -r "${_mandir}"; then
  2489.         _manpath="${_manpath}:${_mandir}";
  2490.         fi;
  2491.       done;
  2492.     done;
  2493.   fi;
  2494.  
  2495.   # append some default directories
  2496.   for d in /usr/local/share/man /usr/local/man \
  2497.             /usr/share/man /usr/man \
  2498.             /usr/X11R6/man /usr/openwin/man \
  2499.             /opt/share/man /opt/man \
  2500.             /opt/gnome/man /opt/kde/man; do
  2501.     if obj _manpath path_not_contains "$d" && obj d is_dir; then
  2502.       _manpath="${_manpath}:$d";
  2503.     fi;
  2504.   done;
  2505.  
  2506.   _MAN_PATH="${_manpath}";
  2507.   eval "${return_ok}";
  2508. } # manpath_set_from_path()
  2509.  
  2510.  
  2511. ########################################################################
  2512. landmark '9: obj_*()';
  2513. ########################################################################
  2514.  
  2515. ########################################################################
  2516. # obj (<object> <call_name> <arg>...)
  2517. #
  2518. # This works like a method (object function) call for an object.
  2519. # Run "<call_name> $<object> <arg> ...".
  2520. #
  2521. # The first argument represents an object whose data is given as first
  2522. # argument to <call_name>().
  2523. #
  2524. # Argument: >=2
  2525. #           <object>: variable name
  2526. #           <call_name>: a program or function name
  2527. #
  2528. obj()
  2529. {
  2530.   func_check obj '>=' 2 "$@";
  2531.   local func;
  2532.   local var;
  2533.   if is_empty "$2"; then
  2534.     error "obj(): function name is empty."
  2535.   else
  2536.     func="$2";
  2537.   fi;
  2538.   eval arg1='"${'$1'}"';
  2539.   shift;
  2540.   shift;
  2541.   eval "${func}"' "${arg1}" "$@"';
  2542. }
  2543.  
  2544.  
  2545. ########################################################################
  2546. # obj_data (<object>)
  2547. #
  2548. # Print the data of <object>, i.e. the content of $<object>.
  2549. # For possible later extensions.
  2550. #
  2551. # Arguments: 1
  2552. #            <object>: a variable name
  2553. # Output:    the data of <object>
  2554. #
  2555. obj_data()
  2556. {
  2557.   func_check obj '=' 1 "$@";
  2558.   if is_empty "$1"; then
  2559.     error "obj_data(): object name is empty."
  2560.   fi;
  2561.   eval echo -n '"${'$1'}"';
  2562. }
  2563.  
  2564.  
  2565. ########################################################################
  2566. # obj_from_output (<object> <call_name> <arg>...)
  2567. #
  2568. # Run '$<object>="$(<call_name> <arg>...)"' to set the result of a
  2569. # function call to a global variable.
  2570. #
  2571. # Arguments: >=2
  2572. #            <object>: a variable name
  2573. #            <call_name>: the name of a function or program
  2574. #            <arg>: optional argument to <call_name>
  2575. # Output:    none
  2576. #
  2577. obj_from_output()
  2578. {
  2579.   func_check obj_from_output '>=' 2 "$@";
  2580.   local result_name;
  2581.   if is_empty "$1"; then
  2582.     error "res(): variable name is empty.";
  2583.   elif is_empty "$2"; then
  2584.     error "res(): function name is empty."
  2585.   else
  2586.     result_name="$1";
  2587.   fi;
  2588.   shift;
  2589.   eval "${result_name}"'="$('"$@"')"';
  2590. }
  2591.  
  2592.  
  2593. ########################################################################
  2594. # obj_set (<object> <data>)
  2595. #
  2596. # Set the data of <object>, i.e. call "$<object>=<data>".
  2597. #
  2598. # Arguments: 2
  2599. #            <object>: a variable name
  2600. #            <data>: a string
  2601. # Output::   none
  2602. #
  2603. obj_set()
  2604. {
  2605.   func_check obj_set '=' 2 "$@";
  2606.   if is_empty "$1"; then
  2607.     error "obj_set(): object name is empty."
  2608.   fi;
  2609.   eval "$1"='"$2"';
  2610. }
  2611.  
  2612.  
  2613. ########################################################################
  2614. # path_chop (<path>)
  2615. #
  2616. # Remove unnecessary colons from path.
  2617. #
  2618. # Argument: 1, a colon separated path.
  2619. # Output:   path without leading, double, or trailing colons.
  2620. #
  2621. path_chop()
  2622. {
  2623.   func_check path_chop = 1 "$@";
  2624.   local _res;
  2625.  
  2626.   # replace multiple colons by a single colon `:'
  2627.   # remove leading and trailing colons
  2628.   echo -n "$1" | sed -e 's/:::*/:/g' |
  2629.                  sed -e 's/^:*//' |
  2630.                  sed -e 's/:*$//';
  2631.   eval "${return_ok}";
  2632. }
  2633.  
  2634.  
  2635. ########################################################################
  2636. # path_clean (<path>)
  2637. #
  2638. # Remove non-existing directories from a colon-separated list.
  2639. #
  2640. # Argument: 1, a colon separated path.
  2641. # Output:   colon-separated list of existing directories.
  2642. #
  2643. path_clean()
  2644. {
  2645.   func_check path_clean = 1 "$@";
  2646.   local _arg;
  2647.   local _dir;
  2648.   local _res;
  2649.   local i;
  2650.   if is_not_equal "$#" 1; then
  2651.     error 'path_clean() needs 1 argument.';
  2652.   fi;
  2653.   _arg="$1";
  2654.   eval set -- "$(path_split "${_arg}")";
  2655.   _res="";
  2656.   for i in "$@"; do
  2657.     if obj i is_not_empty \
  2658.        && obj _res path_not_contains "$i" \
  2659.        && obj i is_dir;
  2660.     then
  2661.       case "$i" in
  2662.         ?*/) _res="${_res}$(dirname_chop "$i")"; ;;
  2663.         *)  _res="${_res}:$i";
  2664.       esac;
  2665.     fi;
  2666.   done;
  2667.   if path_chop "${_res}"; then
  2668.     eval "${return_ok}";
  2669.   else
  2670.     eval "${return_badk}";
  2671.   fi;
  2672. }
  2673.  
  2674.  
  2675. ########################################################################
  2676. # path_contains (<path> <dir>)
  2677. #-
  2678. # Test whether `dir' is contained in `path', a list separated by `:'.
  2679. #
  2680. # Arguments : 2 arguments.
  2681. # Return    : `0' if arg2 is substring of arg1, `1' otherwise.
  2682. #
  2683. path_contains()
  2684. {
  2685.   func_check path_contains = 2 "$@";
  2686.   case ":$1:" in
  2687.     *":$2:"*)
  2688.       eval "${return_yes}";
  2689.       ;;
  2690.     *)
  2691.       eval "${return_no}";
  2692.       ;;
  2693.   esac;
  2694.   eval "${return_ok}";
  2695. }
  2696.  
  2697.  
  2698. ########################################################################
  2699. # path_not_contains (<path> <dir>)
  2700. #-
  2701. # Test whether `dir' is not contained in colon separated `path'.
  2702. #
  2703. # Arguments : 2 arguments.
  2704. #
  2705. path_not_contains()
  2706. {
  2707.   func_check path_not_contains = 2 "$@";
  2708.   if path_contains "$1" "$2"; then
  2709.     eval "${return_no}";
  2710.   else
  2711.     eval "${return_yes}";
  2712.   fi;
  2713.   eval "${return_ok}";
  2714. }
  2715.  
  2716.  
  2717. ########################################################################
  2718. # path_split (<path>)
  2719. #
  2720. # In `path' escape white space and replace each colon by a space.
  2721. #
  2722. # Arguments: 1: a colon-separated path
  2723. # Output:    the resulting list, process with `eval set --'
  2724. #
  2725. path_split()
  2726. {
  2727.   func_check path_split = 1 "$@";
  2728.   list_from_split "$1" ':';
  2729.   eval "${return_ok}";
  2730. }
  2731.  
  2732.  
  2733. ########################################################################
  2734. landmark '10: register_*()';
  2735. ########################################################################
  2736.  
  2737. ########################################################################
  2738. # register_file (<filename>)
  2739. #
  2740. # Write a found file and register the title element.
  2741. #
  2742. # Arguments: 1: a file name
  2743. # Output: none
  2744. #
  2745. register_file()
  2746. {
  2747.   func_check register_file = 1 "$@";
  2748.   if is_empty "$1"; then
  2749.     error 'register_file(): file name is empty';
  2750.   fi;
  2751.   if is_equal "$1" '-'; then
  2752.     to_tmp "${_TMP_STDIN}";
  2753.     register_title '-';
  2754.   else
  2755.     to_tmp "$1";
  2756.     register_title "$(base_name "$1")";
  2757.   fi;
  2758.   eval "${return_ok}";
  2759. }
  2760.  
  2761.  
  2762. ########################################################################
  2763. # register_title (<filespec>)
  2764. #
  2765. # Create title element from <filespec> and append to $_REGISTERED_TITLE
  2766. #
  2767. # Globals: $_REGISTERED_TITLE (rw)
  2768. #
  2769. register_title()
  2770. {
  2771.   func_check register_title = 1 "$@";
  2772.   local _title;
  2773.   if is_empty "$1"; then
  2774.     eval "${return_ok}";
  2775.   fi;
  2776.   _title="$(base_name "$1")";    # remove directory part
  2777.   
  2778.   # remove extension `.gz'
  2779.   _title="$(echo -n "${_title}" | sed -e 's/\.gz$//')";
  2780.   # remove extension `.Z'
  2781.   _title="$(echo -n "${_title}" | sed -e 's/\.Z$//')";
  2782.  
  2783.   if obj _title is_empty; then
  2784.     eval "${return_ok}";
  2785.   fi;
  2786.   _REGISTERED_TITLE="${_REGISTERED_TITLE} ${_title}";
  2787.   eval "${return_ok}";
  2788. }
  2789.  
  2790.  
  2791. ########################################################################
  2792. # reset ()
  2793. #
  2794. # Reset the variables that can be affected by options to their default.
  2795. #
  2796. #
  2797. # Defined in section `Preset' after the rudimentary shell tests.
  2798.  
  2799.  
  2800. ########################################################################
  2801. # save_stdin ()
  2802. #
  2803. # Store standard input to temporary file (with decompression).
  2804. #
  2805. if obj _HAS_COMPRESSION is_yes; then
  2806.   save_stdin()
  2807.   {
  2808.     local _f;
  2809.     func_check save_stdin = 0 "$@";
  2810.      _f="${_TMP_DIR}"/INPUT;
  2811.     cat >"${_f}";
  2812.     catz "${_f}" >"${_TMP_STDIN}";
  2813.     rm -f "${_f}";
  2814.     eval "${return_ok}";
  2815.   }
  2816. else
  2817.   save_stdin()
  2818.   {
  2819.     func_check save_stdin = 0 "$@";
  2820.     cat >"${_TMP_STDIN}";
  2821.     eval "${return_ok}";
  2822.   }
  2823. fi;
  2824.  
  2825.  
  2826. ########################################################################
  2827. landmark '11: stack_*()';
  2828. ########################################################################
  2829.  
  2830. ########################################################################
  2831. # string_contains (<string> <part>)
  2832. #
  2833. # Test whether `part' is contained in `string'.
  2834. #
  2835. # Arguments : 2 text arguments.
  2836. # Return    : `0' if arg2 is substring of arg1, `1' otherwise.
  2837. #
  2838. string_contains()
  2839. {
  2840.   func_check string_contains = 2 "$@";
  2841.   case "$1" in
  2842.     *"$2"*)
  2843.       eval "${return_yes}";
  2844.       ;;
  2845.     *)
  2846.       eval "${return_no}";
  2847.       ;;
  2848.   esac;
  2849.   eval "${return_ok}";
  2850. }
  2851.  
  2852.  
  2853. ########################################################################
  2854. # string_not_contains (<string> <part>)
  2855. #
  2856. # Test whether `part' is not substring of `string'.
  2857. #
  2858. # Arguments : 2 text arguments.
  2859. # Return    : `0' if arg2 is substring of arg1, `1' otherwise.
  2860. #
  2861. string_not_contains()
  2862. {
  2863.   func_check string_not_contains = 2 "$@";
  2864.   if string_contains "$1" "$2"; then
  2865.     eval "${return_no}";
  2866.   else
  2867.     eval "${return_yes}";
  2868.   fi;
  2869.   eval "${return_ok}";
  2870. }
  2871.  
  2872.  
  2873. ########################################################################
  2874. landmark '12: tmp_*()';
  2875. ########################################################################
  2876.  
  2877. ########################################################################
  2878. # tmp_cat ()
  2879. #
  2880. # output the temporary cat file (the concatenation of all input)
  2881. #
  2882. tmp_cat()
  2883. {
  2884.   cat "${_TMP_CAT}";
  2885. }
  2886.  
  2887.  
  2888. ########################################################################
  2889. # tmp_create (<suffix>?)
  2890. #
  2891. # create temporary file
  2892. #
  2893. # It's safe to use the shell process ID together with a suffix to
  2894. # have multiple temporary files.
  2895. #
  2896. # Output : name of created file
  2897. #
  2898. tmp_create()
  2899. {
  2900.   func_check tmp_create '<=' 1 "$@";
  2901.   local _tmp;
  2902.   # the output file does not have `,' as first character
  2903.   _tmp="${_TMP_DIR}/,$1";
  2904.   echo -n >"${_tmp}";
  2905.   echo -n "${_tmp}";        # output file name
  2906.   eval "${return_ok}";
  2907. }
  2908.  
  2909.  
  2910. ########################################################################
  2911. # to_tmp (<filename>)
  2912. #
  2913. # print file (decompressed) to the temporary cat file
  2914. #
  2915. to_tmp()
  2916. {
  2917.   func_check to_tmp = 1 "$@";
  2918.   if is_file "$1"; then
  2919.     if obj _OPT_LOCATION is_yes; then
  2920.       echo2 "$1";
  2921.     fi;
  2922.     if obj _OPT_WHATIS is_yes; then
  2923.       what_is "$1" >>"${_TMP_CAT}";
  2924.     else
  2925.       catz "$1" >>"${_TMP_CAT}";
  2926.     fi;
  2927.   else
  2928.     error "to_tmp(): could not read file \`$1'.";
  2929.   fi;
  2930.   eval "${return_ok}";
  2931. }
  2932.  
  2933.  
  2934. ########################################################################
  2935. # trap_clean ()
  2936. #
  2937. # disable trap on all exit codes ($_ALL_EXIT)
  2938. #
  2939. # Arguments: 0
  2940. # Globals:   $_ALL_EXIT
  2941. #
  2942. trap_clean()
  2943. {
  2944.   func_check trap_clean = 0 "$@";
  2945.   local i;
  2946.   for i in ${_ALL_EXIT}; do
  2947.     trap "" "$i" 2>/dev/null || true;
  2948.   done;
  2949.   eval "${return_ok}";
  2950. }
  2951.  
  2952.  
  2953. ########################################################################
  2954. # trap_set (<functionname>)
  2955. #
  2956. # call function on all exit codes ($_ALL_EXIT)
  2957. #
  2958. # Arguments: 1 (name of a shell function)
  2959. # Globals:   $_ALL_EXIT
  2960. #
  2961. trap_set()
  2962. {
  2963.   func_check trap_set = 1 "$@";
  2964.   local i;
  2965.   for i in ${_ALL_EXIT}; do
  2966.     trap "$1" "$i" 2>/dev/null || true;
  2967.   done;
  2968.   eval "${return_ok}";
  2969. }
  2970.  
  2971.  
  2972. ########################################################################
  2973. # usage ()
  2974. #
  2975. # print usage information to stderr; for groffer option --help.
  2976. #
  2977. usage()
  2978. {
  2979.   func_check usage = 0 "$@";
  2980.   echo;
  2981.   version;
  2982.   echo 'Usage: '"${_PROGRAM_NAME}"' [option]... [filespec]...';
  2983.   cat <<EOF
  2984.  
  2985. Display roff files, standard input, and/or Unix manual pages with a X
  2986. Window viewer or in several text modes.  All input is decompressed
  2987. on-the-fly with all formats that gzip can handle.
  2988.  
  2989. "filespec" is one of
  2990.   "filename"       name of a readable file
  2991.   "-"              for standard input
  2992.   "man:name.n"     man page "name" in section "n"
  2993.   "man:name"       man page "name" in first section found
  2994.   "name.n"         man page "name" in section "n"
  2995.   "name"           man page "name" in first section found
  2996. and some more (see groffer(1) for details).
  2997.  
  2998. -h --help        print this usage message.
  2999. -Q --source      output as roff source.
  3000. -T --device=name pass to groff using output device "name".
  3001. -v --version     print version information.
  3002. -V               display the groff execution pipe instead of formatting.
  3003. -X --X --x       display with "gxditview" using groff -X.
  3004. -Z --ditroff --intermediate-output
  3005.                  generate groff intermediate output without 
  3006.                  post-processing and viewing, like groff -Z.
  3007. All other short options are interpreted as "groff" formatting options.
  3008.  
  3009. The most important groffer long options are
  3010.  
  3011. --apropos=name   start man's "apropos" program for "name".
  3012. --apropos-data=name
  3013.                  "apropos" for "name" in man's data sections 4, 5, 7.
  3014. --apropos-devel=name
  3015.                  "apropos" for "name" in development sections 2, 3, 9.
  3016. --apropos-progs=name
  3017.                  "apropos" for "name" in man's program sections 1, 6, 8.
  3018. --auto           choose mode automatically from the default mode list.
  3019. --default        reset all options to the default value.
  3020. --default-modes=mode1,mode2,...
  3021.                  set sequence of automatically tried modes.
  3022. --dvi            display in a viewer for TeX device independent format.
  3023. --dvi-viewer     choose the viewer program for dvi mode.
  3024. --groff          process like groff, disable viewing features.
  3025. --help           display this helping output.
  3026. --html --www     display in a web browser.
  3027. --html-viewer    choose the web browser for www mode.
  3028. --man            check file parameters first whether they are man pages.
  3029. --mode=auto|dvi|groff|html|pdf|ps|source|text|tty|www|x|X
  3030.                  choose display mode.
  3031. --no-man         disable man-page facility.
  3032. --pager=program  preset the paging program for tty mode.
  3033. --pdf            display in a PDF viewer.
  3034. --pdf-viewer     choose the viewer program for pdf mode.
  3035. --ps             display in a Postscript viewer.
  3036. --ps-viewer      choose the viewer program for ps mode.
  3037. --shell          specify shell under which to run this program.
  3038. --text           output in a text device without a pager.
  3039. --tty            display with a pager on text terminal even when in X.
  3040. --www-viewer     same as --html-viewer
  3041. --x-viewer       choose viewer program for x mode (X mode).
  3042. --X-viewer       same as "--xviewer".
  3043.  
  3044. The usual X Windows toolkit options transformed into GNU long options
  3045. --background=color, --bd=size, --bg=color, --bordercolor=color,
  3046. --borderwidth=size, --bw=size, --display=Xdisplay, --fg=color,
  3047. --fn=font, --font=font, --foreground=color, --geometry=geom, --iconic,
  3048. --resolution=dpi, --rv, --title=text, --xrm=resource
  3049.  
  3050. Long options of GNU "man"
  3051.  --all, --ascii, --ditroff, --extension=suffix, --locale=language,
  3052. --local-file=name, --location, --manpath=dir1:dir2:...,
  3053. --sections=s1:s2:..., --systems=s1,s2,..., --whatis, --where, ...
  3054.  
  3055. EOF
  3056.   eval "${return_ok}";
  3057. }
  3058.  
  3059.  
  3060. ########################################################################
  3061. # version ()
  3062. #
  3063. # print version information to stderr
  3064. #
  3065. version()
  3066. {
  3067.   func_check version = 0 "$@";
  3068.   echo2 "${_PROGRAM_NAME} ${_PROGRAM_VERSION} of ${_LAST_UPDATE}";
  3069.   # also display groff's version, but not the called subprograms
  3070.   groff -v 2>&1 | sed -e '/^ *$/q' | sed -e '1s/^/is part of /' >&2;  
  3071. }
  3072.  
  3073.  
  3074. ########################################################################
  3075. # warning (<string>)
  3076. #
  3077. # Print warning to stderr
  3078. #
  3079. warning()
  3080. {
  3081.   echo2 "warning: $*";
  3082. }
  3083.  
  3084.  
  3085. ########################################################################
  3086. # what_is (<filename>)
  3087. #
  3088. # Interpret <filename> as a man page and display its `whatis'
  3089. # information as a fragment written in the groff language.
  3090. #
  3091. what_is()
  3092. {
  3093.   func_check what_is = 1 "$@";
  3094.   local _res;
  3095.   local _dot;
  3096.   if is_not_file "$1"; then
  3097.     error "what_is(): argument is not a readable file."
  3098.   fi;
  3099.   _dot='^\.['"${_SPACE}${_TAB}"']*';
  3100.   echo '.br';
  3101.   echo "$1: ";
  3102.     echo '.br';
  3103.   echo -n '  ';
  3104.   # grep the line containing `.TH' macro, if any
  3105.   _res="$(catz "$1" | sed -e '/'"${_dot}"'TH /p
  3106. d')";
  3107.   if obj _res is_not_empty; then    # traditional man style
  3108.     # get the text between the first and the second `.SH' macro, by
  3109.     # - delete up to first .SH;
  3110.     # - of this, print everything up to next .SH, and delete the rest;
  3111.     # - of this, delete the final .SH line;
  3112.     catz "$1" | sed -e '1,/'"${_dot}"'SH/d' \
  3113.               | sed -e '1,/'"${_dot}"'SH/p
  3114. d' \
  3115.               | sed -e '/'"${_dot}"'SH/d';
  3116.     eval "${return_ok}";
  3117.   fi;
  3118.   # grep the line containing `.Dd' macro, if any
  3119.   _res="$(catz "$1" | sed -e '/'"${_dot}"'Dd /p
  3120. d')";
  3121.   if obj _res is_not_empty; then    # BSD doc style
  3122.     # get the text between the first and the second `.Nd' macro, by
  3123.     # - delete up to first .Nd;
  3124.     # - of this, print everything up to next .Nd, and delete the rest;
  3125.     # - of this, delete the final .Nd line;
  3126.     catz "$1" | sed -e '1,/'"${_dot}"'Nd/d' \
  3127.               | sed -e '1,/'"${_dot}"'Nd/p
  3128. d' \
  3129.               | sed -e '/'"${_dot}"'Nd/d';
  3130.     eval "${return_ok}";
  3131.   fi;
  3132.   echo 'is not a man page.';
  3133.   eval "${return_bad}";
  3134. }
  3135.  
  3136.  
  3137. ########################################################################
  3138. # where (<program>)
  3139. #
  3140. # Output path of a program if in $PATH.
  3141. #
  3142. # Arguments : >=1 (empty allowed)
  3143. #   more args are ignored, this allows to specify progs with arguments
  3144. # Return    : `0' if arg1 is a program in $PATH, `1' otherwise.
  3145. #
  3146. where()
  3147. {
  3148.   func_check where '>=' 1 "$@";
  3149.   local _file;
  3150.   local _arg;
  3151.   local p;
  3152.   _arg="$1";
  3153.   if obj _arg is_empty; then
  3154.     eval "${return_bad}";
  3155.   fi;
  3156.   case "${_arg}" in
  3157.     /*)
  3158.       if test -f "${_arg}" && test -x "${_arg}"; then
  3159.         eval "${return_ok}";
  3160.       else
  3161.         eval "${return_bad}";
  3162.       fi;
  3163.       ;;
  3164.   esac;
  3165.   eval set -- "$(path_split "${PATH}")";
  3166.   for p in "$@"; do
  3167.     case "$p" in
  3168.       */) _file=${p}${_arg}; ;;
  3169.       *)  _file=${p}/${_arg}; ;;
  3170.     esac;
  3171.     if test -f "${_file}" && test -x "${_file}"; then
  3172.       echo -n "${_file}";
  3173.       eval "${return_ok}";
  3174.     fi;
  3175.   done;
  3176.   eval "${return_bad}";
  3177. }
  3178.  
  3179.  
  3180. ########################################################################
  3181. #                              main
  3182. ########################################################################
  3183.  
  3184. # The main area contains the following parts:
  3185. # - main_init(): initialize temporary files and set exit trap
  3186. # - parse $MANOPT
  3187. # - main_parse_args(): argument parsing
  3188. # - determine display mode
  3189. # - process filespec arguments
  3190. # - setup X resources
  3191. # - do the displaying
  3192.  
  3193. # These parts are implemented as functions, being defined below in the
  3194. # sequence they are called in the main() function.
  3195.  
  3196.  
  3197. #######################################################################
  3198. # main_init ()
  3199. #
  3200. # set exit trap and create temporary files
  3201. #
  3202. # Globals: $_TMP_CAT, $_TMP_STDIN
  3203. #
  3204. landmark '13: main_init()';
  3205. main_init()
  3206. {
  3207.   func_check main_init = 0 "$@";
  3208.   # call clean_up() on any signal
  3209.   trap_set clean_up;
  3210.  
  3211.   # determine temporary directory
  3212.   umask 000;
  3213.   _TMP_DIR='';
  3214.   for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \
  3215.            "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.';
  3216.   do
  3217.     if is_not_empty "$d"; then
  3218.       if obj d is_dir && obj d is_writable; then
  3219.         _TMP_DIR="$(mktemp -d "${d}/${_PROGRAM_NAME}.XXXXXX")"
  3220.         if test $? = 0; then
  3221.           break;
  3222.         else
  3223.           _TMP_DIR='';
  3224.       continue;
  3225.       fi;
  3226.       fi;
  3227.       if obj _TMP_DIR is_not_writable; then
  3228.     _TMP_DIR='';
  3229.     continue;
  3230.       fi;
  3231.     fi;
  3232.   done;
  3233.   unset d;
  3234.   if obj _TMP_DIR is_empty; then
  3235.     error "Couldn't create a directory for storing temporary files.";
  3236.   fi;
  3237.  
  3238.   _TMP_CAT="$(tmp_create groffer_cat)";
  3239.   _TMP_STDIN="$(tmp_create groffer_input)";
  3240.  
  3241.   # groffer configuration files
  3242.   for f in ${_CONFFILES}; do
  3243.     if obj f is_file; then
  3244.       echo '_groffer_opt=""' >>${_TMP_CAT};
  3245.       # collect the lines starting with a minus
  3246.       cat "$f" | sed -e \
  3247.         '/^[     ]*\(-.*\)$/s//_groffer_opt="${_groffer_opt} \1"'/ \
  3248.         >>${_TMP_CAT};
  3249.       # prepend the collected information to $GROFFER_OPT
  3250.       echo 'GROFFER_OPT="${_groffer_opt} ${GROFFER_OPT}"' >>${_TMP_CAT};
  3251.     fi;
  3252.   done;
  3253.   . "${_TMP_CAT}";
  3254.   _TMP_CAT="$(tmp_create groffer_cat)";
  3255.  
  3256.   eval "${return_ok}";
  3257. } # main_init()
  3258.  
  3259.  
  3260. ########################################################################
  3261. # main_parse_MANOPT ()
  3262. #
  3263. # Parse $MANOPT to retrieve man options, but only if it is a non-empty
  3264. # string; found man arguments can be overwritten by the command line.
  3265. #
  3266. # Globals:
  3267. #   in: $MANOPT, $_OPTS_MANOPT_*
  3268. #   out: $_MANOPT_*
  3269. #   in/out: $GROFFER_OPT
  3270. #
  3271. landmark '14: main_parse_MANOPT()';
  3272. main_parse_MANOPT()
  3273. {
  3274.   func_check main_parse_MANOPT = 0 "$@";
  3275.   local _opt;
  3276.   local _list;
  3277.   _list='';
  3278.   if obj MANOPT is_not_empty; then
  3279.     MANOPT="$(echo -n "${MANOPT}" | \
  3280.       sed -e 's/^'"${_SPACE}${_SPACE}"'*//')";
  3281.   fi;
  3282.   if obj MANOPT is_empty; then
  3283.     eval "${return_ok}";
  3284.   fi;
  3285.   # add arguments in $MANOPT by mapping them to groffer options
  3286.   eval set -- "$(list_from_cmdline \
  3287.     _OPTS_MANOPT_SHORT_NA _OPTS_MANOPT_SHORT_ARG \
  3288.     _OPTS_MANOPT_LONG_NA _OPTS_MANOPT_LONG_ARG \
  3289.     "${MANOPT}")";
  3290.   until test "$#" -le 0 || is_equal "$1" '--'; do
  3291.     _opt="$1";
  3292.     shift;
  3293.     case "${_opt}" in
  3294.       -7|--ascii)
  3295.         list_append _list '--ascii';
  3296.         ;;
  3297.       -a|--all)
  3298.         list_append _list '--all';
  3299.         ;;
  3300.       -c|--catman)
  3301.         do_nothing;
  3302.         shift;
  3303.         ;;
  3304.       -d|--debug)
  3305.         list_append _list '--debug';
  3306.         ;;
  3307.       -D|--default)
  3308.         # undo all man options so far
  3309.         _list='';
  3310.         ;;
  3311.       -e|--extension)
  3312.         list_append _list '--extension';
  3313.         shift;
  3314.         ;;
  3315.       -f|--whatis)
  3316.         list_append _list '--whatis';
  3317.         shift;
  3318.         ;;
  3319.       -h|--help)
  3320.         do_nothing;
  3321.         shift;
  3322.         ;;
  3323.       -k|--apropos)
  3324.     # groffer's --apropos takes an argument, but man's does not, so
  3325.         do_nothing;
  3326.         shift;
  3327.         ;;
  3328.       -l|--local-file)
  3329.         list_append _list '--local-file';
  3330.         ;;
  3331.       -L|--locale)
  3332.         list_append _list '--locale' "$1";
  3333.         shift;
  3334.         ;;
  3335.       -m|--systems)
  3336.         list_append _list '--systems' "$1";
  3337.         shift;
  3338.         ;;
  3339.       -M|--manpath)
  3340.         list_append _list '--manpath' "$1";
  3341.         shift;
  3342.         ;;
  3343.       -p|--preprocessor)
  3344.         do_nothing;
  3345.         shift;
  3346.         ;;
  3347.       -P|--pager|--tty-viewer)
  3348.         list_append _list '--pager' "$1";
  3349.         shift;
  3350.         ;;
  3351.       -r|--prompt)
  3352.         do_nothing;
  3353.         shift;
  3354.         ;;
  3355.       -S|--sections)
  3356.         list_append _list '--sections' "$1";
  3357.         shift;
  3358.         ;;
  3359.       -t|--troff)
  3360.         do_nothing;
  3361.         shift;
  3362.         ;;
  3363.       -T|--device)
  3364.         list_append _list '-T' "$1";
  3365.         shift;
  3366.         ;;
  3367.       -u|--update)
  3368.         do_nothing;
  3369.         shift;
  3370.         ;;
  3371.       -V|--version)
  3372.         do_nothing;
  3373.         ;;
  3374.       -w|--where|--location)
  3375.         list_append _list '--location';
  3376.         ;;
  3377.       -Z|--ditroff)
  3378.         list_append _list '-Z' "$1";
  3379.         shift;
  3380.         ;;
  3381.       # ignore all other options
  3382.     esac;
  3383.   done;
  3384.   # append the 2 lists in $_list and $GROFFER_OPT to $GROFFER_OPT
  3385.   if obj GROFFER_OPT is_empty; then
  3386.     GROFFER_OPT="${_list}";
  3387.   elif obj _list is_not_empty; then
  3388.     GROFFER_OPT="${_list} ${GROFFER_OPT}";
  3389.   fi;
  3390.   eval "${return_ok}";
  3391. } # main_parse_MANOPT()
  3392.  
  3393.  
  3394. ########################################################################
  3395. # main_parse_args (<command_line_args>*)
  3396. #
  3397. # Parse arguments; process options and filespec parameters
  3398. #
  3399. # Arguments: pass the command line arguments unaltered.
  3400. # Globals:
  3401. #   in:  $_OPTS_*
  3402. #   out: $_OPT_*, $_ADDOPTS, $_FILEARGS
  3403. #
  3404. landmark '15: main_parse_args()';
  3405. main_parse_args()
  3406. {
  3407.   func_check main_parse_args '>=' 0 "$@";
  3408.   local _arg;
  3409.   local _code;
  3410.   local _dpi;
  3411.   local _longopt;
  3412.   local _mode;
  3413.   local _opt;
  3414.   local _optchar;
  3415.   local _optarg;
  3416.   local _opts;
  3417.   local _string;
  3418.  
  3419.   eval set -- "${GROFFER_OPT}" '"$@"';
  3420.  
  3421.   eval set -- "$(list_from_cmdline \
  3422.    _OPTS_CMDLINE_SHORT_NA _OPTS_CMDLINE_SHORT_ARG \
  3423.    _OPTS_CMDLINE_LONG_NA _OPTS_CMDLINE_LONG_ARG \
  3424.    "$@")";
  3425.  
  3426. # By the call of `eval', unnecessary quoting was removed.  So the
  3427. # positional shell parameters ($1, $2, ...) are now guaranteed to
  3428. # represent an option or an argument to the previous option, if any;
  3429. # then a `--' argument for separating options and
  3430. # parameters; followed by the filespec parameters if any.
  3431.  
  3432. # Note, the existence of arguments to options has already been checked.
  3433. # So a check for `$#' or `--' should not be done for arguments.
  3434.  
  3435.   until test "$#" -le 0 || is_equal "$1" '--'; do
  3436.     _opt="$1";            # $_opt is fed into the option handler
  3437.     shift;
  3438.     case "${_opt}" in
  3439.       -h|--help)
  3440.         usage;
  3441.         leave;
  3442.         ;;
  3443.       -Q|--source)        # output source code (`Quellcode').
  3444.         _OPT_MODE='source';
  3445.         ;;
  3446.       -T|--device|--troff-device) # device; arg
  3447.         _OPT_DEVICE="$1";
  3448.         _check_device_with_mode;
  3449.         shift;
  3450.         ;;
  3451.       -v|--version)
  3452.         version;
  3453.         leave;
  3454.         ;;
  3455.       -V)
  3456.         _OPT_V='yes';
  3457.         ;;
  3458.       -Z|--ditroff|--intermediate-output) # groff intermediate output
  3459.         _OPT_Z='yes';
  3460.         ;;
  3461.       -X|--X|--x)
  3462.         _OPT_MODE=x;
  3463.         ;;
  3464.       -?)
  3465.         # delete leading `-'
  3466.         _optchar="$(echo -n "${_opt}" | sed -e 's/^.//')";
  3467.         if list_has _OPTS_GROFF_SHORT_NA "${_optchar}";
  3468.         then
  3469.           list_append _ADDOPTS_GROFF "${_opt}";
  3470.         elif list_has _OPTS_GROFF_SHORT_ARG "${_optchar}";
  3471.         then
  3472.           list_append _ADDOPTS_GROFF "${_opt}" "$1";
  3473.           shift;
  3474.         else
  3475.           error "Unknown option : \`$1'";
  3476.         fi;
  3477.         ;;
  3478.       --all)
  3479.           _OPT_ALL="yes";
  3480.           ;;
  3481.       --ascii)
  3482.         list_append _ADDOPTS_GROFF '-mtty-char';
  3483.         if obj _mode is_empty; then
  3484.           _mode='text';
  3485.         fi;
  3486.         ;;
  3487.       --apropos)        # run `apropos'
  3488.     apropos_run "$1";
  3489.         _code="$?";
  3490.         clean_up;
  3491.         exit "${_code}";
  3492.         ;;
  3493.       --apropos-data)        # run `apropos' for data sections
  3494.     apropos_run "$1" | grep '^[^(]*([457])';
  3495.         _code="$?";
  3496.         clean_up;
  3497.         exit "${_code}";
  3498.         ;;
  3499.       --apropos-devel)        # run `apropos' for development sections
  3500.     apropos_run "$1" | grep '^[^(]*([239])';
  3501.         _code="$?";
  3502.         clean_up;
  3503.         exit "${_code}";
  3504.         ;;
  3505.       --apropos-progs)        # run `apropos' for program sections
  3506.     apropos_run "$1" | grep '^[^(]*([168])';
  3507.         _code="$?";
  3508.         clean_up;
  3509.         exit "${_code}";
  3510.         ;;
  3511.       --auto)            # the default automatic mode
  3512.         _mode='';
  3513.         ;;
  3514.       --bd)            # border color for viewers, arg;
  3515.         _OPT_BD="$1";
  3516.         shift;
  3517.         ;;
  3518.       --bg|--backgroud)        # background color for viewers, arg;
  3519.         _OPT_BG="$1";
  3520.         shift;
  3521.         ;;
  3522.       --bw)            # border width for viewers, arg;
  3523.         _OPT_BW="$1";
  3524.         shift;
  3525.         ;;
  3526.       --default)        # reset variables to default
  3527.         reset;
  3528.         ;;
  3529.       --default-modes)        # sequence of modes in auto mode; arg
  3530.         _OPT_DEFAULT_MODES="$1";
  3531.         shift;
  3532.         ;;
  3533.       --debug)            # buggy, only for development
  3534.         _OPT_DEBUG='yes';
  3535.         ;;
  3536.       --display)        # set X display, arg
  3537.         _OPT_DISPLAY="$1";
  3538.         shift;
  3539.         ;;
  3540.       --dvi)
  3541.         _OPT_MODE='dvi';
  3542.         ;;
  3543.       --dvi-viewer)        # viewer program for dvi mode; arg
  3544.         _OPT_VIEWER_DVI="$1";
  3545.         shift;
  3546.         ;;
  3547.       --extension)        # the extension for man pages, arg
  3548.         _OPT_EXTENSION="$1";
  3549.         shift;
  3550.         ;;
  3551.       --fg|--foreground)    # foreground color for viewers, arg;
  3552.         _OPT_FG="$1";
  3553.         shift;
  3554.         ;;
  3555.       --fn|--font)        # set font for viewers, arg;
  3556.         _OPT_FN="$1";
  3557.         shift;
  3558.         ;;
  3559.       --geometry)        # window geometry for viewers, arg;
  3560.         _OPT_GEOMETRY="$1";
  3561.         shift;
  3562.         ;;
  3563.       --groff)
  3564.         _OPT_MODE='groff';
  3565.         ;;
  3566.       --html|--www)        # display with web browser
  3567.         _OPT_MODE=html;
  3568.         ;;
  3569.       --html-viewer|--www-viewer) # viewer program for html mode; arg
  3570.         _OPT_VIEWER_HTML="$1";
  3571.         shift;
  3572.         ;;
  3573.       --iconic)            # start viewers as icons
  3574.         _OPT_ICONIC='yes';
  3575.         ;;
  3576.       --locale)            # set language for man pages, arg
  3577.         # argument is xx[_territory[.codeset[@modifier]]] (ISO 639,...)
  3578.         _OPT_LANG="$1";
  3579.         shift;
  3580.         ;;
  3581.       --local-file)        # force local files; same as `--no-man'
  3582.         _MAN_FORCE='no';
  3583.         _MAN_ENABLE='no';
  3584.         ;;
  3585.       --location|--where)    # print file locations to stderr
  3586.         _OPT_LOCATION='yes';
  3587.         ;;
  3588.       --man)            # force all file params to be man pages
  3589.         _MAN_ENABLE='yes';
  3590.         _MAN_FORCE='yes';
  3591.         ;;
  3592.       --manpath)        # specify search path for man pages, arg
  3593.         # arg is colon-separated list of directories
  3594.         _OPT_MANPATH="$1";
  3595.         shift;
  3596.         ;;
  3597.       --mode)            # display mode
  3598.         _arg="$1";
  3599.         shift;
  3600.         case "${_arg}" in
  3601.           auto|'')        # search mode automatically among default
  3602.         _mode='';
  3603.             ;;
  3604.           groff)        # pass input to plain groff
  3605.             _mode='groff';
  3606.             ;;
  3607.           html|www)        # display with a web browser
  3608.             _mode='html';
  3609.             ;;
  3610.           dvi)            # display with xdvi viewer
  3611.             _mode='dvi';
  3612.             ;;
  3613.           pdf)            # display with PDF viewer
  3614.             _mode='pdf';
  3615.             ;;
  3616.           ps)            # display with Postscript viewer
  3617.             _mode='ps';
  3618.             ;;
  3619.           text)            # output on terminal
  3620.             _mode='text';
  3621.             ;;
  3622.           tty)            # output on terminal
  3623.             _mode='tty';
  3624.             ;;
  3625.           X|x)            # output on X roff viewer
  3626.             _mode='x';
  3627.             ;;
  3628.           Q|source)        # display source code
  3629.             _mode="source";
  3630.             ;;
  3631.       *)
  3632.             error "unknown mode ${_arg}";
  3633.             ;;
  3634.         esac;
  3635.         _OPT_MODE="${_mode}";
  3636.         ;;
  3637.       --no-location)        # disable former call to `--location'
  3638.         _OPT_LOCATION='yes';
  3639.         ;;
  3640.       --no-man)            # disable search for man pages
  3641.         # the same as --local-file
  3642.         _MAN_FORCE="no";
  3643.         _MAN_ENABLE="no";
  3644.         ;;
  3645.       --pager)            # set paging program for tty mode, arg
  3646.         _OPT_PAGER="$1";
  3647.         shift;
  3648.         ;;
  3649.       --pdf)
  3650.         _OPT_MODE='pdf';
  3651.         ;;
  3652.       --pdf-viewer)        # viewer program for ps mode; arg
  3653.         _OPT_VIEWER_PDF="$1";
  3654.         shift;
  3655.         ;;
  3656.       --ps)
  3657.         _OPT_MODE='ps';
  3658.         ;;
  3659.       --ps-viewer)        # viewer program for ps mode; arg
  3660.         _OPT_VIEWER_PS="$1";
  3661.         shift;
  3662.         ;;
  3663.       --resolution)        # set resolution for X devices, arg
  3664.         _arg="$1";
  3665.         shift;
  3666.         case "${_arg}" in
  3667.           75|75dpi)
  3668.             _dpi=75;
  3669.             ;;
  3670.           100|100dpi)
  3671.             _dpi=100;
  3672.             ;;
  3673.           *)
  3674.             error "only resoutions of 75 or 100 dpi are supported";
  3675.             ;;
  3676.         esac;
  3677.         _OPT_RESOLUTION="${_dpi}";
  3678.         ;;
  3679.       --rv)
  3680.         _OPT_RV='yes';
  3681.         ;;
  3682.       --sections)        # specify sections for man pages, arg
  3683.         # arg is colon-separated list of section names
  3684.         _OPT_SECTIONS="$1";
  3685.         shift;
  3686.         ;;
  3687.       --shell)
  3688.         shift;
  3689.         ;;
  3690.       --systems)        # man pages for different OS's, arg
  3691.         # argument is a comma-separated list
  3692.         _OPT_SYSTEMS="$1";
  3693.         shift;
  3694.         ;;
  3695.       --text)            # text mode without pager
  3696.         _OPT_MODE=text;
  3697.         ;;
  3698.       --title)            # title for X viewers; arg
  3699.         _OPT_TITLE="$1";
  3700.         shift;
  3701.         ;;
  3702.       --tty)            # tty mode, text with pager
  3703.         _OPT_MODE=tty;
  3704.         ;;
  3705.       --text-device|--tty-device) # device for tty mode; arg
  3706.         _OPT_TEXT_DEVICE="$1";
  3707.         shift;
  3708.         ;;
  3709.       --whatis)
  3710.         _OPT_WHATIS='yes';
  3711.         ;;
  3712.       --xrm)            # pass X resource string, arg;
  3713.         list_append _OPT_XRM "$1";
  3714.         shift;
  3715.         ;;
  3716.       --x-viewer|--X-viewer)    # viewer program for x mode; arg
  3717.         _OPT_VIEWER_X="$1";
  3718.         shift;
  3719.         ;;
  3720.       *)
  3721.         error 'error on argument parsing : '"\`$*'";
  3722.         ;;
  3723.     esac;
  3724.   done;
  3725.   shift;            # remove `--' argument
  3726.  
  3727.   if obj _DEBUG is_not_yes; then
  3728.     if obj _OPT_DEBUG is_yes; then
  3729.       _DEBUG='yes';
  3730.     fi;
  3731.   fi;
  3732.  
  3733.   # Remaining arguments are file names (filespecs).
  3734.   # Save them to list $_FILEARGS
  3735.   if is_equal "$#" 0; then    # use "-" for standard input
  3736.     set -- '-';
  3737.   fi;
  3738.   _FILEARGS='';
  3739.   list_append _FILEARGS "$@";
  3740.   if list_has _FILEARGS '-'; then
  3741.     save_stdin;
  3742.   fi;
  3743.   # $_FILEARGS must be retrieved with `eval set -- "$_FILEARGS"'
  3744.   eval "${return_ok}";
  3745. } # main_parse_args()
  3746.  
  3747. # Called from main_parse_args() because double `case' is not possible.
  3748. # Globals: $_OPT_DEVICE, $_OPT_MODE
  3749. _check_device_with_mode()
  3750. {
  3751.   func_check _check_device_with_mode = 0 "$@";
  3752.   case "${_OPT_DEVICE}" in
  3753.     dvi)
  3754.       _OPT_MODE=dvi;
  3755.       eval "${return_ok}";
  3756.       ;;
  3757.     html)
  3758.       _OPT_MODE=html;
  3759.       eval "${return_ok}";
  3760.       ;;
  3761.     lbp|lj4)
  3762.       _OPT_MODE=groff;
  3763.       eval "${return_ok}";
  3764.       ;;
  3765.     ps)
  3766.       _OPT_MODE=ps;
  3767.       eval "${return_ok}";
  3768.       ;;
  3769.     ascii|cp1047|latin1|utf8)
  3770.       if obj _OPT_MODE is_not_equal text; then
  3771.         _OPT_MODE=tty;        # default text mode
  3772.       fi;
  3773.       eval "${return_ok}";
  3774.       ;;
  3775.     X*)
  3776.       _OPT_MODE=x;
  3777.       eval "${return_ok}";
  3778.       ;;
  3779.     *)                # unknown device, go to groff mode
  3780.       _OPT_MODE=groff;
  3781.       eval "${return_ok}";
  3782.       ;;
  3783.   esac;
  3784.   eval "${return_error}";
  3785. }
  3786.  
  3787.  
  3788. ########################################################################
  3789. # main_set_mode ()
  3790. #
  3791. # Determine the display mode.
  3792. #
  3793. # Globals:
  3794. #   in:  $DISPLAY, $_OPT_MODE, $_OPT_DEVICE
  3795. #   out: $_DISPLAY_MODE
  3796. #
  3797.  
  3798. # _get_first_prog (<proglist>)
  3799. #
  3800. # Retrieve first argument that represents an existing program in $PATH.
  3801. # Local function for main_set_mode().
  3802. #
  3803. # Arguments: 1; a comma-separated list of commands (with options),
  3804. #               like $_VIEWER_*.
  3805. #
  3806. # Return  : `1' if none found, `0' if found.
  3807. # Output  : the argument that succeded.
  3808. #
  3809. landmark '16: main_set_mode()';
  3810. main_set_mode()
  3811. {
  3812.   func_check main_set_mode = 0 "$@";
  3813.   local m;
  3814.   local _modes;
  3815.   local _viewer;
  3816.   local _viewers;
  3817.  
  3818.   # handle apropos
  3819.   if obj _OPT_APROPOS is_not_empty; then
  3820.     apropos "${_OPT_APROPOS}";
  3821.     _code="$?";
  3822.     clean_up;
  3823.     exit "${_code}";
  3824.   fi;
  3825.   if obj _OPT_APROPOS_DATA is_not_empty; then
  3826.     apropos "$@" | grep '^[^(]*([457])';
  3827.     _code="$?";
  3828.     clean_up;
  3829.     exit "${_code}";
  3830.   fi;
  3831.   if obj _OPT_APROPOS_DEVEL is_not_empty; then
  3832.     apropos "$@" | grep '^[^(]*([239])';
  3833.     _code="$?";
  3834.     clean_up;
  3835.     exit "${_code}";
  3836.   fi;
  3837.   if obj _OPT_APROPOS_PROGS is_not_empty; then
  3838.     apropos "$@" | grep '^[^(]*([168])';
  3839.     _code="$?";
  3840.     clean_up;
  3841.     exit "${_code}";
  3842.   fi;
  3843.  
  3844.   # set display
  3845.   if obj _OPT_DISPLAY is_not_empty; then
  3846.     DISPLAY="${_OPT_DISPLAY}";
  3847.   fi;
  3848.  
  3849.   if obj _OPT_V is_yes; then
  3850.     _DISPLAY_MODE='groff';
  3851.     list_append _ADDOPTS_GROFF '-V';
  3852.   fi;
  3853.   if obj _OPT_Z is_yes; then
  3854.     _DISPLAY_MODE='groff';
  3855.     list_append _ADDOPTS_GROFF '-Z';
  3856.   fi;
  3857.   if obj _OPT_MODE is_equal 'groff'; then
  3858.     _DISPLAY_MODE='groff';
  3859.   fi;
  3860.   if obj _DISPLAY_MODE is_equal 'groff'; then
  3861.     eval "${return_ok}";
  3862.   fi;
  3863.  
  3864.   if obj _OPT_MODE is_equal 'source'; then
  3865.     _DISPLAY_MODE='source';
  3866.     eval "${return_ok}";
  3867.   fi;
  3868.  
  3869.   case "${_OPT_MODE}" in
  3870.     '')                # automatic mode
  3871.       case "${_OPT_DEVICE}" in
  3872.         X*)
  3873.           if obj DISPLAY is_empty; then
  3874.             error "no X display found for device ${_OPT_DEVICE}";
  3875.           fi;
  3876.           _DISPLAY_MODE='x';
  3877.           eval "${return_ok}";
  3878.           ;;
  3879.         ascii|cp1047|latin1|utf8)
  3880.           if obj _DISPLAY_MODE is_not_equal 'text'; then
  3881.             _DISPLAY_MODE='tty';
  3882.           fi;
  3883.           eval "${return_ok}";
  3884.           ;;
  3885.       esac;
  3886.       if obj DISPLAY is_empty; then
  3887.         _DISPLAY_MODE='tty';
  3888.         eval "${return_ok}";
  3889.       fi;
  3890.  
  3891.       if obj _OPT_DEFAULT_MODES is_empty; then
  3892.         _modes="${_DEFAULT_MODES}";
  3893.       else
  3894.         _modes="${_OPT_DEFAULT_MODES}";
  3895.       fi;
  3896.       ;;
  3897.     text)
  3898.       _DISPLAY_MODE='text';
  3899.       eval "${return_ok}";
  3900.       ;;
  3901.     tty)
  3902.       _DISPLAY_MODE='tty';
  3903.       eval "${return_ok}";
  3904.       ;;
  3905.     *)                # display mode was given
  3906.       if obj DISPLAY is_empty; then
  3907.         error "you must be in X Window for ${_OPT_MODE} mode.";
  3908.       fi;
  3909.       _modes="${_OPT_MODE}";
  3910.       ;;
  3911.   esac;
  3912.  
  3913.   # only viewer modes are left
  3914.   eval set -- "$(list_from_split "${_modes}" ',')";
  3915.   while test "$#" -gt 0; do
  3916.     m="$1";
  3917.     shift;
  3918.     case "$m" in
  3919.       text)
  3920.         _DISPLAY_MODE='text';
  3921.         eval "${return_ok}";
  3922.         ;;
  3923.       tty)
  3924.         _DISPLAY_MODE='tty';
  3925.         eval "${return_ok}";
  3926.         ;;
  3927.       x)
  3928.         if obj _OPT_VIEWER_X is_not_empty; then
  3929.           _viewers="${_OPT_VIEWER_X}";
  3930.         else
  3931.           _viewers="${_VIEWER_X}";
  3932.         fi;
  3933.         _viewer="$(_get_first_prog "${_viewers}")";
  3934.         if is_not_equal "$?" 0; then
  3935.           continue;
  3936.         fi;
  3937.         _DISPLAY_PROG="${_viewer}";
  3938.         _DISPLAY_MODE='x';
  3939.         eval "${return_ok}";
  3940.         ;;
  3941.       dvi)
  3942.         if obj _OPT_VIEWER_DVI is_not_empty; then
  3943.           _viewers="${_OPT_VIEWER_DVI}";
  3944.         else
  3945.           _viewers="${_VIEWER_DVI}";
  3946.         fi;
  3947.         _viewer="$(_get_first_prog "${_viewers}")";
  3948.         if is_not_equal "$?" 0; then
  3949.           continue;
  3950.         fi;
  3951.         _DISPLAY_PROG="${_viewer}";
  3952.         _DISPLAY_MODE="dvi";
  3953.         eval "${return_ok}";
  3954.         ;;
  3955.       pdf)
  3956.         if obj _OPT_VIEWER_PDF is_not_empty; then
  3957.           _viewers="${_OPT_VIEWER_PDF}";
  3958.         else
  3959.           _viewers="${_VIEWER_PDF}";
  3960.         fi;
  3961.         _viewer="$(_get_first_prog "${_viewers}")";
  3962.         if is_not_equal "$?" 0; then
  3963.           continue;
  3964.         fi;
  3965.         _DISPLAY_PROG="${_viewer}";
  3966.         _DISPLAY_MODE="pdf";
  3967.         eval "${return_ok}";
  3968.         ;;
  3969.       ps)
  3970.         if obj _OPT_VIEWER_PS is_not_empty; then
  3971.           _viewers="${_OPT_VIEWER_PS}";
  3972.         else
  3973.           _viewers="${_VIEWER_PS}";
  3974.         fi;
  3975.         _viewer="$(_get_first_prog "${_viewers}")";
  3976.         if is_not_equal "$?" 0; then
  3977.           continue;
  3978.         fi;
  3979.         _DISPLAY_PROG="${_viewer}";
  3980.         _DISPLAY_MODE="ps";
  3981.         eval "${return_ok}";
  3982.         ;;
  3983.       html)
  3984.         if obj _OPT_VIEWER_HTML is_not_empty; then
  3985.           _viewers="${_OPT_VIEWER_HTML}";
  3986.         else
  3987.           _viewers="${_VIEWER_HTML}";
  3988.         fi;
  3989.         _viewer="$(_get_first_prog "${_viewers}")";
  3990.         if is_not_equal "$?" 0; then
  3991.           continue;
  3992.         fi;
  3993.         _DISPLAY_PROG="${_viewer}";
  3994.         _DISPLAY_MODE=html;
  3995.         eval "${return_ok}";
  3996.         ;;
  3997.     esac;
  3998.   done;
  3999.   error "no suitable display mode found.";
  4000. }
  4001.  
  4002. _get_first_prog()
  4003. {
  4004.   local i;
  4005.   if is_equal "$#" 0; then
  4006.     error "_get_first_prog() needs 1 argument.";
  4007.   fi;
  4008.   if is_empty "$1"; then
  4009.     return "${_BAD}";
  4010.   fi;
  4011.   eval set -- "$(list_from_split "$1" ',')";
  4012.   for i in "$@"; do
  4013.     if obj i is_empty; then
  4014.       continue;
  4015.     fi;
  4016.     if is_prog "$(get_first_essential $i)"; then
  4017.       echo -n "$i";
  4018.       return "${_GOOD}";
  4019.     fi;
  4020.   done;
  4021.   return "${_BAD}";
  4022. } # main_set_mode()
  4023.  
  4024.  
  4025. #######################################################################
  4026. # main_do_fileargs ()
  4027. #
  4028. # Process filespec arguments in $_FILEARGS.
  4029. #
  4030. # Globals:
  4031. #   in: $_FILEARGS (process with `eval set -- "$_FILEARGS"')
  4032. #
  4033. landmark '17: main_do_fileargs()';
  4034. main_do_fileargs()
  4035. {
  4036.   func_check main_do_fileargs = 0 "$@";
  4037.   local _exitcode;
  4038.   local _filespec;
  4039.   local _name;
  4040.   _exitcode="${_BAD}";
  4041.   eval set -- "${_FILEARGS}";
  4042.   unset _FILEARGS;
  4043.   # temporary storage of all input to $_TMP_CAT
  4044.   while test "$#" -ge 2; do
  4045.     # test for `s name' arguments, with `s' a 1-char standard section
  4046.     _filespec="$1";
  4047.     shift;
  4048.     case "${_filespec}" in
  4049.       '')
  4050.         continue;
  4051.         ;;
  4052.       '-')
  4053.         if register_file '-'; then
  4054.           _exitcode="${_GOOD}";
  4055.         fi;
  4056.         continue;
  4057.         ;;
  4058.       ?)
  4059.         if list_has_not _MAN_AUTO_SEC "${_filespec}"; then
  4060.           if do_filearg "${_filespec}"; then
  4061.             _exitcode="${_GOOD}";
  4062.           fi;
  4063.           continue;
  4064.         fi;
  4065.         _name="$1";
  4066.         case "${_name}" in
  4067.           */*|man:*|*\(*\)|*."${_filespec}")
  4068.             if do_filearg "${_filespec}"; then
  4069.               _exitcode="${_GOOD}";
  4070.             fi;
  4071.             continue;
  4072.             ;;
  4073.         esac;
  4074.         if do_filearg "man:${_name}(${_filespec})"; then
  4075.           _exitcode="${_GOOD}";
  4076.           shift;
  4077.           continue;
  4078.         else
  4079.           if do_filearg "${_filespec}"; then
  4080.             _exitcode="${_GOOD}";
  4081.           fi;
  4082.           continue;
  4083.         fi;
  4084.         ;;
  4085.       *)
  4086.         if do_filearg "${_filespec}"; then
  4087.           _exitcode="${_GOOD}";
  4088.         fi;
  4089.         continue;
  4090.         ;;
  4091.     esac;
  4092.   done;                # end of `s name' test
  4093.   while test "$#" -gt 0; do
  4094.     _filespec="$1";
  4095.     shift;
  4096.     if do_filearg "${_filespec}"; then
  4097.       _exitcode="${_GOOD}";
  4098.     fi;
  4099.   done;
  4100.   rm -f "${_TMP_STDIN}";
  4101.   if is_equal "${_exitcode}" "${_BAD}"; then
  4102.     eval "${return_bad}";
  4103.   fi;
  4104.   eval "${return_ok}";
  4105. } # main_do_fileargs()
  4106.  
  4107.  
  4108. ########################################################################
  4109. # main_set_resources ()
  4110. #
  4111. # Determine options for setting X resources with $_DISPLAY_PROG.
  4112. # Globals: $_DISPLAY_PROG, $_OUTPUT_FILE_NAME
  4113. #
  4114. landmark '18: main_set_resources()';
  4115. main_set_resources()
  4116. {
  4117.   func_check main_set_resources = 0 "$@";
  4118.   local _prog;            # viewer program
  4119.   local _rl;            # resource list
  4120.   local n;
  4121.   _title="$(get_first_essential \
  4122.                 "${_OPT_TITLE}" "${_REGISTERED_TITLE}")";
  4123.   _OUTPUT_FILE_NAME='';
  4124.   set -- ${_title};
  4125.   until is_equal "$#" 0; do 
  4126.     n="$1";
  4127.     case "$n" in
  4128.     '')
  4129.       continue;
  4130.       ;;
  4131.     ,*)
  4132.       n="$(echo -n "$1" | sed -e '/^,,*/s///')";
  4133.       ;;
  4134.     esac
  4135.     if obj n is_empty; then
  4136.       continue;
  4137.     fi;
  4138.     if obj _OUTPUT_FILE_NAME is_not_empty; then
  4139.       _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME},";
  4140.     fi;
  4141.     _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME}$n";
  4142.     shift;
  4143.   done;
  4144.   case "${_OUTPUT_FILE_NAME}" in
  4145.   '')
  4146.     _OUTPUT_FILE_NAME='-';
  4147.     ;;
  4148.   ,*)
  4149.     error "$_OUTPUT_FILE_NAME starts with a comma.";
  4150.     ;;
  4151.   esac;
  4152.   _OUTPUT_FILE_NAME="${_TMP_DIR}/${_OUTPUT_FILE_NAME}";
  4153.  
  4154.   if obj _DISPLAY_PROG is_empty; then # for example, for groff mode
  4155.     _DISPLAY_ARGS='';
  4156.     eval "${return_ok}";
  4157.   fi;
  4158.  
  4159.   set -- ${_DISPLAY_PROG};
  4160.   _prog="$(base_name "$1")";
  4161.   _rl='';
  4162.   if obj _OPT_BD is_not_empty; then
  4163.     case "${_prog}" in
  4164.       ghostview|gv|gxditview|xditview|xdvi)
  4165.         list_append _rl '-bd' "${_OPT_BD}";
  4166.         ;;
  4167.     esac;
  4168.   fi;
  4169.   if obj _OPT_BG is_not_empty; then
  4170.     case "${_prog}" in
  4171.       ghostview|gv|gxditview|xditview|xdvi)
  4172.         list_append _rl '-bg' "${_OPT_BG}";
  4173.         ;;
  4174.       xpdf)
  4175.         list_append _rl '-papercolor' "${_OPT_BG}";
  4176.         ;;
  4177.     esac;
  4178.   fi;
  4179.   if obj _OPT_BW is_not_empty; then
  4180.     case "${_prog}" in
  4181.       ghostview|gv|gxditview|xditview|xdvi)
  4182.         _list_append _rl '-bw' "${_OPT_BW}";
  4183.         ;;
  4184.     esac;
  4185.   fi;
  4186.   if obj _OPT_FG is_not_empty; then
  4187.     case "${_prog}" in
  4188.       ghostview|gv|gxditview|xditview|xdvi)
  4189.         list_append _rl '-fg' "${_OPT_FG}";
  4190.         ;;
  4191.     esac;
  4192.   fi;
  4193.   if is_not_empty "${_OPT_FN}"; then
  4194.     case "${_prog}" in
  4195.       ghostview|gv|gxditview|xditview|xdvi)
  4196.         list_append _rl '-fn' "${_OPT_FN}";
  4197.         ;;
  4198.     esac;
  4199.   fi;
  4200.   if is_not_empty "${_OPT_GEOMETRY}"; then
  4201.     case "${_prog}" in
  4202.       ghostview|gv|gxditview|xditview|xdvi|xpdf)
  4203.         list_append _rl '-geometry' "${_OPT_GEOMETRY}";
  4204.         ;;
  4205.     esac;
  4206.   fi;
  4207.   if is_empty "${_OPT_RESOLUTION}"; then
  4208.     _OPT_RESOLUTION="${_DEFAULT_RESOLUTION}";
  4209.     case "${_prog}" in
  4210.       gxditview|xditview)
  4211.         list_append _rl '-resolution' "${_DEFAULT_RESOLUTION}";
  4212.         ;;
  4213.       xpdf)
  4214.         case "${_DEFAULT_RESOLUTION}" in
  4215.           75)
  4216.             # 72dpi is '100'
  4217.             list_append _rl '-z' '104';
  4218.             ;;
  4219.           100)
  4220.             list_append _rl '-z' '139';
  4221.             ;;
  4222.         esac;
  4223.         ;;
  4224.     esac;
  4225.   else
  4226.     case "${_prog}" in
  4227.       ghostview|gv|gxditview|xditview|xdvi)
  4228.         list_append _rl '-resolution' "${_OPT_RESOLUTION}";
  4229.         ;;
  4230.       xpdf)
  4231.         case "${_OPT_RESOLUTION}" in
  4232.           75)
  4233.             list_append _rl '-z' '104';
  4234.             # '100' corresponds to 72dpi
  4235.             ;;
  4236.           100)
  4237.             list_append _rl '-z' '139';
  4238.             ;;
  4239.         esac;
  4240.         ;;
  4241.     esac;
  4242.   fi;
  4243.   if is_yes "${_OPT_ICONIC}"; then
  4244.     case "${_prog}" in
  4245.       ghostview|gv|gxditview|xditview|xdvi)
  4246.         list_append _rl '-iconic';
  4247.         ;;
  4248.     esac;
  4249.   fi;
  4250.   if is_yes "${_OPT_RV}"; then
  4251.     case "${_prog}" in
  4252.       ghostview|gv|gxditview|xditview|xdvi)
  4253.         list_append _rl '-rv';
  4254.         ;;
  4255.     esac;
  4256.   fi;
  4257.   if is_not_empty "${_OPT_XRM}"; then
  4258.     case "${_prog}" in
  4259.       ghostview|gv|gxditview|xditview|xdvi|xpdf)
  4260.         eval set -- "{$_OPT_XRM}";
  4261.         for i in "$@"; do
  4262.           list_append _rl '-xrm' "$i";
  4263.         done;
  4264.         ;;
  4265.     esac;
  4266.   fi;
  4267.   if is_not_empty "${_title}"; then
  4268.     case "${_prog}" in
  4269.       gxditview|xditview)
  4270.         list_append _rl '-title' "${_title}";
  4271.         ;;
  4272.     esac;
  4273.   fi;
  4274.   _DISPLAY_ARGS="${_rl}"; 
  4275.  
  4276.   eval "${return_ok}";
  4277. } # main_set_resources
  4278.  
  4279.  
  4280. ########################################################################
  4281. # main_display ()
  4282. #
  4283. # Do the actual display of the whole thing.
  4284. #
  4285. # Globals:
  4286. #   in: $_DISPLAY_MODE, $_OPT_DEVICE,
  4287. #       $_ADDOPTS_GROFF, $_ADDOPTS_POST, $_ADDOPTS_X,
  4288. #       $_REGISTERED_TITLE, $_TMP_CAT,
  4289. #       $_OPT_PAGER $PAGER $_MANOPT_PAGER
  4290. #
  4291. landmark '19: main_display()';
  4292. main_display()
  4293. {
  4294.   func_check main_display = 0 "$@";
  4295.   local p;
  4296.   local _addopts;
  4297.   local _device;
  4298.   local _groggy;
  4299.   local _modefile;
  4300.   local _options;
  4301.   local _pager;
  4302.   local _title;
  4303.   export _addopts;
  4304.   export _groggy;
  4305.   export _modefile;
  4306.  
  4307.   if obj _TMP_CAT is_non_empty_file; then
  4308.     _modefile="${_OUTPUT_FILE_NAME}";
  4309.   else
  4310.     clean_up;
  4311.     eval "${return_ok}";
  4312.   fi;
  4313.   case "${_DISPLAY_MODE}" in
  4314.     groff)
  4315.       _ADDOPTS_GROFF="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
  4316.       if obj _OPT_DEVICE is_not_empty; then
  4317.         _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}";
  4318.       fi;
  4319.       _groggy="$(tmp_cat | eval grog "${_options}")";
  4320.       trap_clean;
  4321.       # start a new shell program to get another process ID.
  4322.       sh -c '
  4323.         set -e;
  4324.         test -f "${_modefile}" && rm -f "${_modefile}";
  4325.         mv "${_TMP_CAT}" "${_modefile}";
  4326.         cat "${_modefile}" | \
  4327.         (
  4328.           clean_up()
  4329.           {
  4330.             if test -d "${_TMP_DIR}"; then
  4331.               rm -f "${_TMP_DIR}"/* || true;
  4332.               rmdir "${_TMP_DIR}";
  4333.             fi;
  4334.           }
  4335.           trap clean_up 0 2>/dev/null || true;
  4336.           eval "${_groggy}" "${_ADDOPTS_GROFF}";
  4337.         ) &'
  4338.       ;;
  4339.     text|tty)
  4340.       case "${_OPT_DEVICE}" in
  4341.         '')
  4342.           _device="$(get_first_essential \
  4343.                      "${_OPT_TEXT_DEVICE}" "${_DEFAULT_TTY_DEVICE}")";
  4344.           ;;
  4345.         ascii|cp1047|latin1|utf8)
  4346.           _device="${_OPT_DEVICE}";
  4347.           ;;
  4348.         *)
  4349.           warning \
  4350.             "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
  4351.           ;;
  4352.       esac;
  4353.       _addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
  4354.       _groggy="$(tmp_cat | grog -T${_device})";
  4355.       if obj _DISPLAY_MODE is_equal 'text'; then
  4356.         tmp_cat | eval "${_groggy}" "${_addopts}";
  4357.       else
  4358.         _pager='';
  4359.         for p in "${_OPT_PAGER}" "${PAGER}" "${_MANOPT_PAGER}" \
  4360.                  'less -r -R' 'more' 'pager' 'cat'; do
  4361.         if is_prog $p; then   # no "" for is_prog() allows args for $p
  4362.           _pager="$p";
  4363.           break;
  4364.         fi;
  4365.         done;
  4366.         if obj _pager is_empty; then
  4367.           error 'no pager program found for tty mode';
  4368.         fi;
  4369.         tmp_cat | eval "${_groggy}" "${_addopts}" | \
  4370.                   eval "${_pager}";
  4371.       fi;
  4372.       clean_up;
  4373.       ;;
  4374.  
  4375.     #### viewer modes
  4376.  
  4377.     dvi)
  4378.       case "${_OPT_DEVICE}" in
  4379.         ''|dvi) do_nothing; ;;
  4380.         *)
  4381.           warning \
  4382.             "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
  4383.           ;;
  4384.       esac;
  4385.       _groggy="$(tmp_cat | grog -Tdvi)";
  4386.       _do_display;
  4387.       ;;
  4388.     html)
  4389.       case "${_OPT_DEVICE}" in
  4390.         ''|html) do_nothing; ;;
  4391.         *)
  4392.           warning \
  4393.             "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
  4394.           ;;
  4395.       esac;
  4396.       _modefile="${_modefile}".html
  4397.       _groggy="$(tmp_cat | grog -Thtml)";
  4398.       _do_display;
  4399.       ;;
  4400.     pdf)
  4401.       case "${_OPT_DEVICE}" in
  4402.         ''|ps)
  4403.           do_nothing;
  4404.           ;;
  4405.         *)
  4406.           warning \
  4407.             "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
  4408.           ;;
  4409.       esac;
  4410.       _modefile="${_modefile}"
  4411.       _groggy="$(tmp_cat | grog -Tps)";
  4412.       trap_clean;
  4413.       # start a new shell program to get another process ID.
  4414.       sh -c '
  4415.         set -e;
  4416.         _psfile="${_modefile}.ps";
  4417.         _modefile="${_modefile}.pdf";
  4418.         test -f "${_psfile}" && rm -f "${_psfile}";
  4419.         test -f "${_modefile}" && rm -f "${_modefile}";
  4420.         cat "${_TMP_CAT}" | \
  4421.           eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_psfile}";
  4422.         gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
  4423.            -sOutputFile="${_modefile}" -c save pop -f "${_psfile}";
  4424.         test -f "${_psfile}" && rm -f "${_psfile}";
  4425.         test -f "${_TMP_CAT}" && rm -f "${_TMP_CAT}";
  4426.         (
  4427.           clean_up() {
  4428.             rm -f "${_modefile}";
  4429.             if test -d "${_TMP_DIR}"; then
  4430.               rm -f "${_TMP_DIR}"/* || true;
  4431.               rmdir "${_TMP_DIR}";
  4432.             fi;
  4433.           }
  4434.           trap clean_up 0 2>/dev/null || true;
  4435.           eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}";
  4436.         ) &'
  4437.       ;;
  4438.     ps)
  4439.       case "${_OPT_DEVICE}" in
  4440.         ''|ps)
  4441.           do_nothing;
  4442.           ;;
  4443.         *)
  4444.           warning \
  4445.             "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
  4446.           ;;
  4447.       esac;
  4448.       _groggy="$(tmp_cat | grog -Tps)";
  4449.       _do_display;
  4450.       ;;
  4451.     source)
  4452.       tmp_cat;
  4453.       clean_up;
  4454.       ;;
  4455.     x)
  4456.       case "${_OPT_DEVICE}" in
  4457.         '')
  4458.           _groggy="$(tmp_cat | grog -Z)";
  4459.           ;;
  4460.         X*|ps)
  4461.           _groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -Z)";
  4462.           ;;
  4463.         *)
  4464.           warning \
  4465.             "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
  4466.           _groggy="$(tmp_cat | grog -Z)";
  4467.           ;;
  4468.       esac;
  4469.       _do_display;
  4470.       ;;
  4471.     *)
  4472.       error "unknown mode \`${_DISPLAY_MODE}'";
  4473.       ;;
  4474.   esac;
  4475.   eval "${return_ok}";
  4476. } # main_display()
  4477.  
  4478. _do_display()
  4479. {
  4480.   func_check _do_display = 0 "$@";
  4481.   trap_clean;
  4482.   # start a new shell program for another process ID and better
  4483.   # cleaning-up of the temporary files.
  4484.   sh -c '
  4485.     set -e;
  4486.     test -f "${_modefile}" && rm -f "${_modefile}";
  4487.     cat "${_TMP_CAT}" | \
  4488.       eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_modefile}";
  4489.     rm -f "${_TMP_CAT}";
  4490.     (
  4491.       clean_up() {
  4492.         if test -d "${_TMP_DIR}"; then
  4493.           rm -f "${_TMP_DIR}"/* || true;
  4494.           rmdir "${_TMP_DIR}";
  4495.         fi;
  4496.       }
  4497.       trap clean_up 0 2>/dev/null || true;
  4498.       eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}";
  4499.     ) &'
  4500. }
  4501.  
  4502.  
  4503. ########################################################################
  4504. # main (<command_line_args>*)
  4505. #
  4506. # The main function for groffer.
  4507. #
  4508. # Arguments:
  4509. #
  4510. main()
  4511. {
  4512.   func_check main '>=' 0 "$@";
  4513.   # Do not change the sequence of the following functions!
  4514.   main_init;
  4515.   main_parse_MANOPT;
  4516.   main_parse_args "$@";
  4517.   main_set_mode;
  4518.   main_do_fileargs;
  4519.   main_set_resources;
  4520.   main_display;
  4521.   eval "${return_ok}";
  4522. }
  4523.  
  4524. landmark '20: end of function definitions';
  4525.  
  4526. ########################################################################
  4527.  
  4528. main "$@";
  4529.